[英]Passing a Struct pointer (with char pointers in body) in C# via P/Ivoke
我在C中有一个.DLL文件。该DLL中所有函数所需的主要结构具有以下形式。
typedef struct
{
char *snsAccessID;
char *snsSecretKey;
char *snsPath;
char *snsTopicName;
char *snsTopicAmazonResourceName;
char *snsDisplayName;
char *snsOwnerId;
} snsTopic, *HSNS;
其中一个功能就是如下:
BOOL SnsOpenTopic(char *accessID, char *secretKey, char *ownerId, char *path, char *topicName, char *displayName, HSNS *snsTopicHandle);
上面的所有char指针都是Input参数。
我在WinCE6 / 7设备上使用C#和.NET CF 3.5。
我尝试使用一个类,然后将指针传递给C函数所需的结构,如下所示:
public class HSNS
{
public string snsAccessID;
public string snsSecretKey;
public string snsPath;
public string snsTopicName;
public string snsTopicAmazonResourceName;
public string snsDisplayName;
public string snsOwnerId;
}
[DllImport("Cloud.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SnsOpenTopic(string accessID, string secretKey, string ownerId, string path, string topicName, string displayName, ref HSNS snsTopicHandle);
使用上面的C#片段会导致抛出NotSupportedException。 我无法弄清楚上面的C#代码有什么问题?
我尝试的另一件事是使用C#的非托管代码。
unsafe public struct HSNS
{
public char *snsAccessID;
public char *snsSecretKey;
public char *snsPath;
public char *snsTopicName;
public char *snsTopicAmazonResourceName;
public char *snsDisplayName;
public char *snsOwnerId;
}
[DllImport("Cloud.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SnsOpenTopic(string accessID, string secretKey, string ownerId, string path, string topicName, string displayName, HSNS *snsTopicHandle);
fixed (HSNS *snsAcsTopicHandle = &snsAcsTopic)
{
if (SnsOpenTopic(AWS_ACCOUNT_ACCESS_ID, AWS_ACCOUNT_SECRET_KEY, AWS_ACCOUNT_OWNER_ID, AWS_SNS_SINGAPORE_REGION, topicName, displayName, snsAcsTopicHandle))
{
}
}
在上面的例子中,在调试中,我可以检查结构内部的指针是否未被填充,在调试视图中,我可以看到无效引用。 无法取消引用指针消息。 其余功能因此而失败。
在上述场景中使用Platform Invoke和Marshalling的正确方法是什么。 我试过在Google上搜索和Stack溢出。 没找到与我类似的用例。
我相信您使用IntPtr作为char *并使用“ref”作为您的结构
[DllImport("Cloud.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean SnsOpenTopic(string accessID, string secretKey, string ownerId, string path, string topicName, string displayName, ref HSNS snsTopicHandle);
[StructLayout(LayoutKind.Sequential)]
public struct HSNS
{
public IntPtr snsAccessID;
public IntPtr snsSecretKey;
public IntPtr snsPath;
public IntPtr snsTopicName;
public IntPtr snsTopicAmazonResourceName;
public IntPtr snsDisplayName;
public IntPtr snsOwnerId;
}
然后,当您想要访问结构结果时,需要将IntPtr封送为字符串。
http://msdn.microsoft.com/en-us/library/7b620dhe.aspx
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(snsTopicHandler.snsPath);
或者http://msdn.microsoft.com/en-us/library/ewyktcaa.aspx
System.Runtime.InteropServices.Marshal.PtrToStringAuto(snsTopicHandler.snsPath);
问题在于编码。 .NET CF 3.5始终使用Unicode编码。 我有DLL中的函数,期望字符指向ASCII中的字符串而不是Unicode。
我是这样做的。
unsafe public struct HSNS
{
public char *snsAccessID;
public char *snsSecretKey;
public char *snsPath;
public char *snsTopicName;
public char *snsTopicAmazonResourceName;
public char *snsDisplayName;
public char *snsOwnerId;
}
[DllImport("Cloud.dll", SetLastError = true)]
public unsafe static extern Boolean SnsOpenTopic(Byte* accessID, Byte* secretKey, Byte* ownerId, Byte* path, Byte* topicName, Byte* displayName, ref HSNS snsAcsTopic);
// Sample of encoding conversion
public Byte[] topicName = Encoding.ASCII.GetBytes("CSharpACSAlert\0");
然后使用下面的指针来修复它
fixed (Byte* ptrTopicName = &topicName[0])
我仍然有一些问题,使其他一些功能工作,但两个主要功能已开始工作。
以下两个帖子帮了很多忙。
http://www.codeproject.com/Articles/5888/An-Introduction-to-P-Invoke-and-Marshaling-on-the
http://www.codeproject.com/Articles/5890/Advanced-P-Invoke-on-the-Microsoft-NET-Compact-Fra
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.