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

San*_*ity 5 c# windows-ce .net-cf-3.5

我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。

typedef struct
{
    char *snsAccessID;      
    char *snsSecretKey;     
    char *snsPath;          
    char *snsTopicName;     
    char *snsTopicAmazonResourceName; 
    char *snsDisplayName;   
    char *snsOwnerId;       
} snsTopic, *HSNS;
Run Code Online (Sandbox Code Playgroud)

其中一个函数仅作为示例,如下所示:

BOOL SnsOpenTopic(char *accessID, char *secretKey, char *ownerId, char *path, char *topicName, char *displayName, HSNS *snsTopicHandle);
Run Code Online (Sandbox Code Playgroud)

上面所有的 char 指针都是输入参数。

我在 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);
Run Code Online (Sandbox Code Playgroud)

使用上面的 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))
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的情况下,在调试中我可以检查结构内的指针没有被填充,并且在调试视图中我可以看到无效引用。无法取消引用指针消息。其余功能因此而失败。

对于上述场景,使用平台调用和编组的正确方法是什么?我尝试过在 Google 和 Stack Overflow 上搜索。没有找到与我类似的用例。

Lou*_*cci 0

我相信您使用 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;       
}
Run Code Online (Sandbox Code Playgroud)

然后,当您想要访问结构结果时,需要将 IntPtr 封送为字符串。

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

System.Runtime.InteropServices.Marshal.PtrToStringAnsi(snsTopicHandler.snsPath);
Run Code Online (Sandbox Code Playgroud)

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

System.Runtime.InteropServices.Marshal.PtrToStringAuto(snsTopicHandler.snsPath);
Run Code Online (Sandbox Code Playgroud)