|
It's important that I know the data structure for the CStringArray . When marshaling data from native to manage code or back, the data must be marshaled in a way that can be represented in both native and managed code. For example, a simple string[] array in manage could would marshal a contiguous array of references (marshaled as pointers) to null-terminated character arrays, something like in this ASCII art:
_____
| a |----->"Points to 'a'"
| b |---+
| c |-+ |
----- | +->"Points to 'b'"
|
|
+--->"Points to 'c'" That's a very generalized representation, but it helps know how to marshal a string[] array. Without knowing how the CStringArray class stores data, it's impossible to tell you how to marshal it for sure.
If you're not sure of the structure of CStringArray , 1) look in the headers for the definition of the class, or 2) tell us where this class is defined. Is it an MFC class, or an ATL class? Is it defined by another library.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
CStringArray is a standard class of Vc++6.0/MFC,not ATL or not my defined class. In my native codes,
there is implemention as follows:
void GetStrings(CStringArray &stringArray)
{
CString a = "a";
CString b= "aaaa";
stringArray.Add(a);
stringArray.Add(b);
}
The length of stringArray is inconstant.
The initial purpose is as follows:
In C# program, I need get some strings which the number of string is
inconstant from a native c++ dll. Because MFC's CStringArary is good,i use
it as export variable.
If CStringArray can not suit me ,how to do in c++ dll?
|
|
|
|
|
If you look at the documentation for the CStringArray class, you'd see that it's declared in atlcoll.h, which you can find in the Vc7\atlmfc\include directory under your VS.NET installation path. Looking at it's definition, you can find that it has fields defined like so:
CString* m_pData;
INT_PTR m_nSize;
INT_PTR m_nMaxSize;
INT_PTR m_nGrowBy; The CString class is defined in cstringt.h, and extends the CSimpleStringT , which contains on member, PXSTR and is defined in atlsimpstr.h. PXSTR is a typedef of a templated class. CString is a platform-specific character set, being ANSI on Windows 9x/Me and Unicode on Windows NT-based platforms like XP.
This means you should be able to define a class like so:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
class CStringArray
{
public string[] m_pData;
IntPtr m_nSize;
IntPtr m_nMaxSize;
IntPtr m_nGrowBy;
} You should declare your P/Invoke method like so:
[DllImport("mydll.dll", CharSet=CharSet.Auto)]
static extern void GetString(out CStringArray strarr); Try this and it should work for you.
You should not expose your P/Invoke method publicly, but instead encapsulate it in a method that is exposed publicly and removes the burden of having to work with natively-defined data, which isn't always so nice to work with in managed code.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
Sorry , it does not work. I will send my examples to you.Please check it and correct it.
|
|
|
|
|
Sorry.I can not upload my example codes online,so just paste it here.
Regular Dll using shared MFC dll:
extern "C" void PASCAL EXPORT GetValues(CStringArray & stringArray)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString a = "a";
CString b = "b";
stringArray.Add(a);
stringArray.Add(b);
}
c# managed codes:
using System;
using System.Runtime.InteropServices;
namespace CSharpProject
{
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
class CStringArray{
public string[] m_pData;
IntPtr m_nSize;
IntPtr m_nMaxSize;
IntPtr m_nGrowBy;
}
class Class1
{
[DllImport("MFCDLL.dll", CharSet=CharSet.Auto)]
static extern void GetValues(out CStringArray strarr);
[STAThread]
static void Main(string[] args)
{
CStringArray stringArray = new CStringArray();
GetValues(out stringArray);
}
}
}
Above codes do not work correctly.
|
|
|
|
|
What about it doesn't work? Is an exception thrown? On what line is the exception thrown (debug your application in VS.NET or use cordbg.exe on the command line)? What's the exception type and message?
Stating that it "doesn't work" doesn't help me diagnose the problem, so I can't provide any advice to you without knowing exactly doesn't work.
Also make sure that "MFCDll.dll" is in a directory referenced in your PATH environment variable. The DLL is loaded using LoadLibrary , which checks the working directory for the application that's loading it, then in directories in the PATH environment variable.
For information about how native DLLs are found, read the documentation[^] for LoadLibrary . If you're interested to know how managed assemblies are located, read How the Runtime Locates Assemblies[^].
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
1, I build a Regular Dll using shared MFC dll as follows:
extern "C" void PASCAL EXPORT GetValues(CStringArray & stringArray)<br />
{<br />
AFX_MANAGE_STATE(AfxGetStaticModuleState());<br />
CString a = "a"; <br />
CString b = "b";<br />
<br />
stringArray.Add(a);<br />
stringArray.Add(b);<br />
}
2,build a c# console project named text.exe as follows:
using System;<br />
using System.Runtime.InteropServices;<br />
<br />
namespace CSharpProject<br />
{<br />
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]<br />
class CStringArray{<br />
public string[] m_pData;<br />
IntPtr m_nSize; <br />
IntPtr m_nMaxSize; <br />
IntPtr m_nGrowBy;<br />
}<br />
<br />
class Class1<br />
{ <br />
[DllImport("MFCDLL.dll", CharSet=CharSet.Auto)]<br />
public static extern void GetValues(out CStringArray strarr);<br />
<br />
[STAThread]<br />
static void Main(string[] args)<br />
{<br />
CStringArray stringArray = new CStringArray();<br />
GetValues(out stringArray); <br />
}<br />
}<br />
}
3, Copy MFCDLL.dll to the directory of text.exe.
4,double press text.exe ,but program throws exception:System.ExecutionEngineException. When debugging the text.exe,variable:stringArray is undefined value.I think maybe there is some problem with the structure of class CStringArray.
P.S.
1. If debugging the program yourself ,you should diagnose the problem.
2. In ..\MFC\include\AFXCOLL.h, In CStringArray,there is:
protected:<br />
CString* m_pData;
int m_nSize;
int m_nMaxSize;
int m_nGrowBy;
so ,i modify your CStringArray:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]<br />
class CStringArray{ <br />
public string[] m_pData;<br />
int m_nSize; <br />
int m_nMaxSize;<br />
int m_nGrowBy;<br />
} But it does not work,too.
Thank you very much.
|
|
|
|
|
One problem could be that the marhsaler must know the size of the array, but one must use MarshalAsAttribute.SizeConst and MarshalAsAttribute.SizeParamIndex only works for marshaling method parameters, not struct fields.
The Marshal class in System.Runtime.InteropServices can be useful for custom marshaling, which you can read about here: http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemRuntimeInteropServicesICustomMarshalerClassTopic.asp[^].
Also, the native code is different from your original code you posted. Since you are not instantiating the CStringArray then you must use ref instead of out in your P/Invoke signature and must instantiate the managed CStringArray . You can read about the differences between ref and out here: http://msdn.microsoft.com/library/en-us/csref/html/vclrfPassingMethodParameters.asp[^]. Since CStringArray is a class, it will be a reference type. Try just leaving off the ref or out and declaring the parameter simply as (CStringArray stringArray) . Typically out and ref are used with struct params, since structs are value types and are passed by-value; or with double pointers for reference types.
Finally, I am not debugging your code. This development community is here to help you learn, but not to do your work. That will never teach anyone anything. Debugging your code and helping to diagnose the problem is what you should be doing and is part of the development lifecycle.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
This is the just problem i meeted. And hidn't solve it until now.
I use a similar class in c# to warp it, but it does't work well too.
And finally i get a wrong result:
I find
the size of CStringArray doesn't equal to marshal_size of the similar class in c#.
And i do it with the attribute of explicit, but ummy, it doesn't work well too.
So, anybody can help me ?
|
|
|
|
|
i have found the code here (http://www.codeproject.com/dotnet/CSharpWhiteboard.asp) ,but it only can be used by two users . unfortunately, i need one which can support many users (i know that it need a server ,and need to use SOCKET) .
how to finish it ??? need to help !
thanks !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
can u send me some useful things about it ?
my email------------- saxon_100@hotmail.com
need helps . i know there are many master-hand
|
|
|
|
|
This appears to be the THIRD time you have asked this question. This first time you received no replies. The second time you received a messsage to say that "your method for asking for help probably isn't the most effective."
I should point out that if you have a question regarding an article (http://www.codeproject.com/dotnet/CSharpWhiteboard.asp[^]) you should ask in the forum of the article. You have not done this.
Secondly, your question ("how to finish it???") requires and answer that will be very time consuming to answer fully. However, a brief look at the article would suggest that it IS finished as the original author only intended to write a 2 person whiteboard.
My: Blog | Photos | Next SQL Presentation
WDevs.com - Open Source Code Hosting, Blogs, FTP, Mail and More
|
|
|
|
|
|
Please post some sample code to which you are referring. Based on what's in the article, I don't understand the context of your question. The exception simply means that the URL is invalid (like "http:domain.com" is invalid) and file:// URLs are typically supported in most cases in the .NET Framework.
However, if you're trying to replace characters in an HTML file that is not XML (and most HTML files on the web are not well-formed and are not XML), then you'll need an SGML parser (SGML is the parent language for both HTML and XML). Use the SgmlReader[^] on GotDotNet, which is a very popular library for reading HTML files and even transcoding to XML (XHTML).
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
i am trying to use following code given on MS site
http://support.microsoft.com/default.aspx?scid=kb;en-us;316063[^]
string filepath = "C:\\Customers.xml";
private void ReplaceSpecialChars(long linenumber)
{
System.IO.StreamReader strm;
string strline;
string strreplace = " ";
string tempfile = "C:\\Temp.xml";
try
{
System.IO.File.Copy(filepath,tempfile,true);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
StreamWriter strmwriter = new StreamWriter(filepath);
instead of giving local file path,i am giving the URL
http://127.0.0.1/file.asp?s=adnan&f=xml[^]
when someone access this URL it gives XML output,i want to parse this output and replace special characters with acceptable characters by XML,forInstance i got a character < in XML and its giving parsing error,i found above mentioned solution by MS and tried ti implement it but it`s working fine for local files but not http URLs
Thanks for your reply
MyBlogs
http://weblogs.com.pk/kadnan
|
|
|
|
|
File.Copy does not accept URLs. To download a file via HTTP (or practically any protocol, so long as a pluggable protocol handler is installed for it) you must use the HttpWebRequest and HttpWebResponse classes, or simply use the WebClient class which encapsulates the former two classes. Read the documentation[^] for HttpWebRequest.GetResponse for an example of the former two classes, and the documentation[^] for WebClient.DownloadFile for example of the latter.
This posting is provided "AS IS" with no warranties, and confers no rights.
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
[My Articles] [My Blog]
|
|
|
|
|
I'm learning how to use C# collections. Can't seem to find the answer on this one, though...
<br />
namespace myNameSpace<br />
{<br />
class ClassA<br />
{<br />
private string key;<br />
private string name;<br />
<br />
}<br />
<br />
class ClassB<br />
{<br />
private HashTable myHashTable;<br />
<br />
myFunction(string key, string name)<br />
{<br />
myHashTable = new HashTable();<br />
ClassA TempClassA = new ClassA(key, name);<br />
myHashTable.Add(TempClassA.key, TempClassA);<br />
}<br />
<br />
<br />
myOtherFuntion(int searchkey)<br />
{<br />
ClassA myClassA = (ClassA)myHashTable[searchkey];<br />
string str = myClassA.name;
myClassA.name = "newname";
}<br />
}<br />
}<br />
The code compiles fine. At that point in runtime, however, I get an error referring to "string str = ca.name;" that says "Object reference not set to an instance of an object." The same error occurs for the line "myClassA.name = "newname";". I would imagine it's a fairly basic syntax error, but I just can't find a suitable example.
Any suggestions?
Thanks for your help.
|
|
|
|
|
tantiboh wrote:
ClassA myClassA = (ClassA)myHashTable[searchkey];
//I need to be able to complete both of the following operations:
string str = myClassA.name; //Causes an exception
myClassA.name = "newname"; //Causes an exception
The reason these two lines fail is that the first line I've quoted does not return a value, so myClassA is null . This is because either (1) the searchkey does not correspond to any key in the HashTable , or (2) the value null is stored for that searchkey .
The most likely explanation is that when you insert something into the HashTable you are using a string , when you try to retrieve something from the HashTable you are using an int . You must be consistent. Choose either a string or an int and stick to it.
My: Blog | Photos | Next SQL Presentation
WDevs.com - Open Source Code Hosting, Blogs, FTP, Mail and More
|
|
|
|
|
Using an int instead of a string was an error in the example I wrote for the thread; that problem doesn't exist in my actualy code.
However, your comment that ClassA is null prompted me to check for that, and it was. So, you've given me a new avenue to investigate.
Thanks for your help!
|
|
|
|
|
I'm using VS.NET 2003. When i use unicode in my control, I must Save As... with Save With Encoding ... How I can config my IDE to default my Encoding. Thank for advances.
Nothing
|
|
|
|
|
|
Can anyone help me get this thing started... I mean what input variables, what output variables do i need? how many files do i need in order to make this thing work? How do i make the output file save as .html? how do i create an option of a random background color for the user? How many arrays do i need in my program? Any help would be nice. Thank you for your time!
|
|
|
|
|
I would start by deciding what kind of web page I'm making.
ZMAN0728 wrote:
How do i make the output file save as .html?
The same thing that you make other files.
ZMAN0728 wrote:
How many arrays do i need in my program?
It depends, what kind of web page are you making?
<italic>Work hard, Work effectively and a bit of luck is the key to success.
|
|
|
|
|
hi all,
I hope any one can help me in this problem...
suppose i have a picture folder .. how i can to get the size of this folder in C# language.
thanks
|
|
|
|
|
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(@"C:\");
System.IO.FileInfo[] files = dir.GetFiles();
long totalsize = 0;
for (int i = 0; i <= files.GetUpperBound(0); i++)
{
totalsize = files[i].Length;
}
MessageBox.Show(totalsize.ToString());
Best of Luck
Forever Developing
|
|
|
|
|
I am trying to have assembly A load assembly B into a seperate domain. It's odd because when I load the assembly into the second AppDomain, it is also loaded into the default domain. So, when I unload the second AppDomain, it doesn't actually unload the assembly. Am I doing something wrong here:
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.Current.SetupInformation.ApplicationBase;
setup.ApplicationName = "Test";
AppDomain domain = AppDomain.CreateDomain("NewDomain", null, setup);
IInterface i = (IInterface)domain.CreateInstanceFromAndUnwrap("AssemblyB.dll", "AssemblyB.Interface");
If I run AppDomain.Current.GetAssemblies() to get the loaded assemblies before I run this code, it does not show AssemblyB loaded. If I run it after, it is loaded in the default domain. If I unload the second domain, it is still loaded in the default domain. No other project in the solution is dependent on AssemblyB, so it shouldn't be loading it into the default domain. Any ideas?
|
|
|
|
|