简体   繁体   English

通过P / Ivoke在C#中传递一个Struct指针(带有char指针)

[英]Passing a Struct pointer (with char pointers in body) in C# via P/Ivoke

I have a .DLL file in C. The primary structure required by all functions in that DLL is of the following form. 我在C中有一个.DLL文件。该DLL中所有函数所需的主要结构具有以下形式。

typedef struct
{
    char *snsAccessID;      
    char *snsSecretKey;     
    char *snsPath;          
    char *snsTopicName;     
    char *snsTopicAmazonResourceName; 
    char *snsDisplayName;   
    char *snsOwnerId;       
} snsTopic, *HSNS;

One of the functions just for example is as follows: 其中一个功能就是如下:

BOOL SnsOpenTopic(char *accessID, char *secretKey, char *ownerId, char *path, char *topicName, char *displayName, HSNS *snsTopicHandle);

All char pointers above are Input parameters. 上面的所有char指针都是Input参数。

I am using C# with .NET CF 3.5 on a WinCE6/7 device. 我在WinCE6 / 7设备上使用C#和.NET CF 3.5。

I have tried using a class and then passing the pointer to the structure required by the C function as follows: 我尝试使用一个类,然后将指针传递给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);

Using the C# snippet above results in NotSupportedException being thrown. 使用上面的C#片段会导致抛出NotSupportedException。 I can't figure out what's wrong with the above C# code? 我无法弄清楚上面的C#代码有什么问题?

Another thing i tried is using unmanaged code with 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))
    {
    }
}

In the above case, in debug i can check the pointers inside the structure are not being populated and in the debug view i can see Invalid Reference. 在上面的例子中,在调试中,我可以检查结构内部的指针是否未被填充,在调试视图中,我可以看到无效引用。 Cannot dereference pointer message. 无法取消引用指针消息。 The rest of the functions fail because of this. 其余功能因此而失败。

What is the correct way to use Platform Invoke and Marshalling for the above scenario. 在上述场景中使用Platform Invoke和Marshalling的正确方法是什么。 I have tried searching on Google and Stack overflow. 我试过在Google上搜索和Stack溢出。 Didn't find a use case similar to mine. 没找到与我类似的用例。

I believe you use IntPtr for char* and "ref" for your structure 我相信您使用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;       
}

Then when you want to access your structures results, you need to marshal the IntPtr to a string. 然后,当您想要访问结构结果时,需要将IntPtr封送为字符串。

http://msdn.microsoft.com/en-us/library/7b620dhe.aspx http://msdn.microsoft.com/en-us/library/7b620dhe.aspx

System.Runtime.InteropServices.Marshal.PtrToStringAnsi(snsTopicHandler.snsPath);

Or http://msdn.microsoft.com/en-us/library/ewyktcaa.aspx 或者http://msdn.microsoft.com/en-us/library/ewyktcaa.aspx

System.Runtime.InteropServices.Marshal.PtrToStringAuto(snsTopicHandler.snsPath);

The problem was with encoding. 问题在于编码。 .NET CF 3.5 uses Unicode encoding throughout. .NET CF 3.5始终使用Unicode编码。 The functions in DLL which I had, expected character pointer to strings in ASCII and not Unicode. 我有DLL中的函数,期望字符指向ASCII中的字符串而不是Unicode。

I did it like this. 我是这样做的。

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");

And then using below to get the pointer and fix it 然后使用下面的指针来修复它

fixed (Byte* ptrTopicName = &topicName[0])

I still have problems with making a few other functions work but the two primary functions have started working. 我仍然有一些问题,使其他一些功能工作,但两个主要功能已开始工作。

The below two posts helped a lot. 以下两个帖子帮了很多忙。

http://www.codeproject.com/Articles/5888/An-Introduction-to-P-Invoke-and-Marshaling-on-the 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 http://www.codeproject.com/Articles/5890/Advanced-P-Invoke-on-the-Microsoft-NET-Compact-Fra

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM