【问题标题】:C++ unmanaged DLL in c#C#中的C++非托管DLL
【发布时间】:2011-09-06 19:30:42
【问题描述】:

我被要求在我的项目中集成网络摄像头 ZoneTrigger。站点中提供的 SDK 是 C++ 也是示例。我已经能够使用一些功能。我被卡住的地方是一个函数,其中 char* 是传递的参数。我做了很多挖掘,才知道必须使用 MarshalAs...

我想从中导入的函数 c++代码

//header file
struct ZT_TRIG_STRUCT 
{
int aSize;      //STRUCT size
int CameraIndex;
int SpotIndex;
int SpotType;
char SpotName[32];
DWORD Dummy[16];
};

typedef int (WINAPI *f_ZT_EnumerateHotSpots)(int SpotIndex, char *Name, int *SpotType);
/*
You application can call this functions to retrieve information about spots by iterating the SpotIndex param.
Name is a pointer to a 32 byte buffer supplied by your application.
SpotType is a pointer to an 32 bit integer in your application.
Return value:
0 = Success, the Name and SpotType have been initialized
1 = Error, we have lost communication with Zone Trigger
2 = Enumaration is over, all spots have been enumerated. Your application should increment SpotIndex until this function returns 2.
*/

//code
//Enumerate current spots in Zone Trigger
int i=0;
char SpotName[32];
int SpotType;
check = ZT_EnumerateHotSpots(i, SpotName, &SpotType);
while (check == 0) 
{
    float sensitivity = ZT_GetSensitivity(i);
    printf("Zone Trigger spot: %s   Sensitivity: %0.1f%%\r\n", SpotName,     sensitivity*100);
    check = ZT_EnumerateHotSpots(++i, SpotName, &SpotType);
}

所以当转换成c#时

[DllImport("ZTcom.dll")]
    private static extern int ZT_EnumerateHotSpots(int i, [MarshalAs(UnmanagedType.LPWStr)]ref string SpotName, ref int SpotType);

 public unsafe struct ZT_TRIG_STRUCT 
    {
        public int aSize;       //STRUCT size
        public int CameraIndex;
        public int SpotIndex;
        public int SpotType;
      public string SpotName ;  
        //[MarshalAs(UnmanagedType.LPStr, SizeConst = 256)] string SpotName;
       // public IntPtr SpotName;
    }

//In code
int i = 0;
 string SpotName;
int SpotType;
check = ZT_EnumerateHotSpots(i, ref SpotName, ref SpotType);

以上行给出:

Exception of type 'System.ExecutionEngineException' was thrown.

错误。

我知道问题出在 SpotName,它是一个字节 [32],如果我不使用 marshalAs,而我只使用 char 它可以工作 n 给出第一个 char.. 它工作正常的代码 n 给出第一个字符如下

 public unsafe struct ZT_TRIG_STRUCT 
    {
        public int aSize;       //STRUCT size
        public int CameraIndex;
        public int SpotIndex;
        public int SpotType;
      public char SpotName ;              
    }

 [DllImport("ZTcom.dll")]
    private static extern int ZT_EnumerateHotSpots(int i, ref char SpotName, ref int SpotType);

 public char SpotName;
int i = 0;
            check = ZT_EnumerateHotSpots(i, ref SpotName, ref SpotType);
            while (check == 0)
            {
                float sensitivity = ZT_GetSensitivity(i);
                textBox1.Text = textBox1.Text + "\r\n" +"Zone Trigger spot: " + SpotName + "   Sensitivity: " + (sensitivity * 100).ToString();
                check = ZT_EnumerateHotSpots(++i, ref SpotName, ref SpotType);
            }

但如果我输入 char[] 它会给出

Method's type signature is not Interop compatible. ERROR

我已经用完了这里的选项....我哪里出错了?我应该使用 MarshalAs 还是 char[] ??? 请帮忙..... 提前谢谢....

【问题讨论】:

  • 为什么ZT_TRIG_STRUCT 被标记为不安全?它不包含不安全的成员。
  • [MarshalAs(UnmanagedType.LPStr, SizeConst = 32)] 字符串 SpotName;不工作?
  • @Preet 内联字符串应该使用UnmanagedType.ByValTStr,而不是LPStr;看我的回答。
  • ZT_TRIG_STRUCT 是其他函数中使用的结构体也包含凸轮的数据,触发我们必须使用上面的函数枚举...

标签: c# c++ dll pinvoke


【解决方案1】:

我看不到你在哪里使用ZT_TRIG_STRUCT,但应该这样声明:

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct ZT_TRIG_STRUCT 
{
    public int aSize;
    public int CameraIndex;
    public int SpotIndex;
    public int SpotType;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
    public string SpotName;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=16)]
    public uint[] Dummy;
}

您遇到的另一个问题是ZT_EnumerateHotSpots 的声明。那应该是:

[DllImport("ZTcom.dll", CharSet=CharSet.Ansi)]
private static extern int ZT_EnumerateHotSpots(
    int SpotIndex, 
    StringBuilder SpotName, 
    out int SpotType
);

当我读到它时,SpotName 实际上是一个输出参数,即你提供一个缓冲区,ZT_EnumerateHotSpots 写入它。

然后你就这样称呼它

int SpotIndex = 0;
StringBuilder SpotName = new StringBuilder(32);
int SpotType;
int result = ZT_EnumerateHotSpots(SpotIndex, SpotName, out SpotType);

【讨论】:

  • 是的,你说得对,这个名字是一个输出参数并且需要一个 StringBuilder。我没有发现,双关语;)。我删除了我的答案并为你的答案投了赞成票。
  • @Sven 谢谢。您回答的另一个小问题是 DWORD 映射到 uint
  • 它们的大小相同,并且由于该成员被称为Dummy,我怀疑这真的很重要。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 2013-01-07
  • 2010-10-14
  • 2011-04-29
相关资源
最近更新 更多