在http://topic.csdn.net/u/20080616/09/56f758f7-78a3-4a5c-8bad-903a5deb0acb.html
一贴中提问到int GetListName(char** pList[])
{
*pList= (char **) malloc (sizeof(char *) * 128);
//返回字符串 组数量
} [DllImport("mydll.dll",EntryPoint="GetListName", SetLastError=true, CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.StdCall)]
public static extern int GetNameList(IntPtr[] pList);
调用
IntPtr[] PtrList =new IntPtr[2]{new IntPtr(0),new IntPtr(0)};
int bn=GetNameList(PtrList);
if(bn>0)
{
IsOk=true;
Drv=Marshal.ReadIntPtr(PtrList[0]);
string as1 =Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(PtrList[0]));
}
能够获得PtrList[0]正确的字符串,但是当返回的字符串是有两组或多组的时候
PtrList[1]永远是0
不知道怎么解决
一贴中提问到int GetListName(char** pList[])
{
*pList= (char **) malloc (sizeof(char *) * 128);
//返回字符串 组数量
} [DllImport("mydll.dll",EntryPoint="GetListName", SetLastError=true, CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.StdCall)]
public static extern int GetNameList(IntPtr[] pList);
调用
IntPtr[] PtrList =new IntPtr[2]{new IntPtr(0),new IntPtr(0)};
int bn=GetNameList(PtrList);
if(bn>0)
{
IsOk=true;
Drv=Marshal.ReadIntPtr(PtrList[0]);
string as1 =Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(PtrList[0]));
}
能够获得PtrList[0]正确的字符串,但是当返回的字符串是有两组或多组的时候
PtrList[1]永远是0
不知道怎么解决
char** str
int nCount= GetUsbDeviceListName(&str);
char* msg=_strdup(strConnectedDevices[1]);
if(nCount>1)
MessageBox(0,msg, 0,0);可以正确获得,但C#里就不行,高手来啊
ref char str
你觉得在C#如何写?
ref IntPtr[]也不行
ref StringBuilder[]也不行
能够获得第一个地址
不知道这个串组地址是否连续的
IntPtr[0]是否整个串组的首地址。
如果是,有什么办法获得偏移地址的串?
IntPtr a1=Marshal.ReadIntPtr(PtrList[0]);
IntPtr a2=(IntPtr)((int)a1+Marshal.SizeOf(bn));这样能计算出。等下试一下结果
理论上,只要malloc分配的内存是连续的,就可以了
最后的计算方法是int bn=0;
IntPtr a1=Marshal.ReadIntPtr(PtrList[0]);
先获得a1指向的字符串的长度len
然后
IntPtr a2=(IntPtr)((int)a1+len*Marshal.SizeOf(bn)); //也即a1+4×len不知道正确不?
LZ在C++的代码赋值本身就有问题,
C++中
*pList= (char **) malloc (sizeof(char *) * 128); 这里实际只给PtrList[0]赋值了,而没有给PtrList[1]赋值。
试下改成用下面的代码,就可使PtrList[1]的值不为0
int GetListName(char** pList[])
{
pList[0] = (char **)malloc (sizeof(char*) * 128);//这里仅是指针数组的指针。
pList[1] = (char **)malloc (sizeof(char*) * 128);
*pList[0] = (char *)malloc (sizeof(char) * 128);//这里才是字符串指针。
*pList[1] = (char *)malloc (sizeof(char) * 128);
strcpy(*pList[0], "abcdefb!!!");
strcpy(*pList[1], "eeeeeeee!!!");
}所以返回的字符串是有两组或多组的时候,完全没有必要传个IntPtr[]数组进去,只传个IntPtr进去就可,记住这个IntPtr的值是指向一个指针数组,该数组的元素才是一个指向字符串的指针。
int GetListName(char** pList[])
{
*pList= (char **) malloc (sizeof(char *) * 128);
//返回字符串 组数量
}
问题一、 采用T a[]传递参数的时候,隐含的意义是传入一个数组。
采用T *a也可以传递数组,但它意义侧重于传入a的指针,这个指针可以指向一串a,也可以是一个a的引用。下列用一些简单的例子解释:
int main(int argc, char* argv[]) // 这是C++常见的入口函数,旧的用法是(int argc, char** argv)
{
*argv = new char[100]; // 用了char* charv[]更强调数组的传入,给argv赋值明显是错误的理解
}void doubleUp(int length, int nums[]) // 传入数组的示例
{
for(int i=0; i<length; i++)
{
nums[i] = nums[i] + nums[i]; // 好的做法,传入数组,同时传入数组的长度
}
}void GetStringSafe(char* buf, int maxLength) // 传入指针的示例
{
StringCbCopyA(buf, maxLength, "safe method call"); // 好的做法
}void GetStringNeedYourCare(char** str)
{
*str = new char[32]; // 比较不好的做法,要特别关注以免内存泄露
StringCbCopyA(*str, 32, "You need to delete me!");
}void Test()
{
char buf[128];
GetStringSafe( buf, 128 ); // 安全的调用
char* result = NULL;
GetStringNeedYourCare( &result );
delete[] result; // 调用者需要释放内存。
}
*pList= (char **) malloc (sizeof(char *) * 128); 违背了调用惯例,调用者也无从知道返回了128个指针。
问题二、
指针的指针不实用。先看看两种给*pList赋值的方法:
int GetListName(char** pList[])
{
*pList= (char **) malloc (sizeof(char *) * 128);
//返回字符串 组数量 char* string1 = new char[32];
StringCbCopyA(string1, 32, "string one");
//pList[0] = &string1; // 错误,string1指针本身(不是它指向的内容)是本地变量。 char** ptrToString1 = new char*; // 需要分配一个指针的指针。
*ptrToString1 = string1;
pList[0] = ptrToString1;
//...
}int GetListName(char** pList[])
{
*pList= (char **) malloc (sizeof(char *) * 128);
//返回字符串 组数量
pList[0] = new char* [8];
pList[0][0] = new char[32];
StringCbCopyA( pList[0][0], 32, "string 00"); pList[0][1] = new char[32];
StringCbCopyA( pList[0][1], 32, "string 01"); //...
pList[0][7] = new char[32];
StringCbCopyA( pList[0][7], 32, "string 07"); //...
}
第一种方法,本意跟char* pList[]一样,无缘无故增加了一个转意,调用者还要多清理一次内存。
第二种方法,传回128个“字符串的数组”,但调用者又如何知道每个“字符串的数组”有多长呢,是上述例子的8个还是80个?这样写函数的方式,内存的分配和释放没有约定,数组的长度无从知道,不要说托管非托管的交互,就是C++客户也难以调用。
dk385
gomoku
两位的回复很有启发,需要些时间认真的消化消化。
gomoku后面提到的“字符串的长度”有多长,应该是可以知道的吧?好像char* char[]遇到"\0"就结束的吧?,
在C#里面也能正确获得一个这个长度,直接Marshal.PtrToStringAnsi(首地址)就是这个字符串的长度了,知道第一个长度,就能知道第二个长度了。
至于这个数组的长度是int GetListName()给返回的。C++的客户也难调用:),这的确。我用c++也搞了很久才调得出来,
对C++不熟,只能达到调用的层次,修改dll有点难度,只能去硬着头皮去调用。然后小心的管理善后:)
感谢两位的帮忙。:)
{
*pList= (char **) malloc (sizeof(char *) * 128);
*pList[0] =strdup("foo");
return 0;
}
public extern static int fnmydll( ref System.IntPtr p );
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
//
// TODO: 在此处添加代码以启动应用程序
//
Console.Read();
System.IntPtr p = System.IntPtr.Zero;
fnmydll( ref p );
System.IntPtr b = (IntPtr)Marshal.PtrToStructure( p , typeof( System.IntPtr )) ;
string str = Marshal.PtrToStringAnsi(b); //str is "foo"
}