【问题标题】:Passing a Struct pointer (with char pointers in body) in C# via P/Ivoke通过 P/Ivoke 在 C# 中传递 Struct 指针(在正文中带有 char 指针)
【发布时间】:2013-07-29 16:40:45
【问题描述】:

我有一个 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);

以上所有字符指针都是输入参数。

我在 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# sn-p 会导致 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))
    {
    }
}

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

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

【问题讨论】:

    标签: c# windows-ce .net-cf-3.5


    【解决方案1】:

    我相信您将 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);
    

    【讨论】:

    • 我尝试了你的建议。不工作。结构中的指针仍未填充。这在 Debug 中很清楚,并且在使用 Marshal.PtrToStringBSTR(snsAcsTopic.snsDisplayName) 时,会引发 NullException。
    • @Sanchayan - 在不了解您的 C 代码的情况下很难提供帮助。 C 中的 char 数组是全局分配的吗?
    【解决方案2】:

    问题在于编码。 .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

    【讨论】:

      猜你喜欢
      • 2012-12-29
      • 2020-08-16
      • 2013-05-06
      • 2020-03-14
      • 2012-03-03
      • 2021-12-14
      • 2013-10-19
      • 2015-04-29
      • 1970-01-01
      相关资源
      最近更新 更多