从C调用dll与C++头#

问题描述:

我想调用一个方法,我有C++头的dll。我从C#调用dll。输入是一个字符串,输出是二进制数据。以下3种方法中的任何一种都可能起作用,我只是不知道如何使它们中的任何一种都起作用。由于我的C#声明,所以他们可能不正确从C调用dll与C++头#

1:我能够得到hGlobal,但我不知道如何从句柄中获取数据。

//CMBT_LL_WINAPI INT DLLPROC LlConvertStringToHGLOBALW(LPCWSTR pszText, _PHGLOBAL phMemory); 
[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); 

2:

[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToBLOBW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
//CMBT_LL_WINAPI INT  DLLPROC LlConvertStringToBLOBW(LPCWSTR pszText, _PUINT8 pBytes, UINT nBytes); 
private static extern int _LlConvertStringToBLOBW(string text, ref IntPtr pBytes, UInt32 nBytes); 

3:

[DllImport("cmll15.dll", EntryPoint = "LlConvertStringToStreamW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
//CMBT_LL_WINAPI INT  DLLPROC LlConvertStringToStreamW(LPCWSTR pszText, _PISTREAM pStream); 
private static extern int _LlConvertStringToStreamW(string text, ref IntPtr pStream); 

更新,这里就是我想我会在最后的代码。

[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    private static extern UIntPtr GlobalSize(IntPtr hMem); 

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    public static extern IntPtr GlobalLock(IntPtr handle); 

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] 
    public static extern IntPtr GlobalUnlock(IntPtr handle); 

    [DllImport("cmll15.dll", EntryPoint = "LlConvertStringToHGLOBALW", CharSet = CharSet.Unicode, ExactSpelling = true)] 
    private static extern int _LlConvertStringToHGlobal32(string text, ref IntPtr handle); 

    private static void Main(string[] args) 
    { 
     IntPtr dataHandle = IntPtr.Zero; 
     _LlConvertStringToHGlobal32(Contents, ref dataHandle); 
     try 
     { 
      var size = (uint) GlobalSize(dataHandle); 
      var array = new byte[size]; 
      IntPtr dataPtr = GlobalLock(dataHandle); 
      try 
      { 
       Marshal.Copy(dataPtr, array, 0, array.Length); 
      } 
      finally 
      { 
       GlobalUnlock(dataPtr); 
      } 

      using (var fs = new FileStream("c:\\file.dat", FileMode.Create)) 
      { 
       fs.Write(array, 0, array.Length); 
      } 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(dataHandle); 
     } 
    } 
+0

你试过编译和运行它们吗?指定问题以便我们理解。 – Nawaz 2011-01-12 09:01:24

+1

如果您已经指定了`CharSet.Unicode`,为什么还要指定`ExactSpelling`和`EntryPoint`?那些是多余的。 – 2011-01-12 09:06:19

+0

我不认为我的问题是将方法从C++转换为C#,但我不知道,我只是向他们展示了它们,因此您可能会发现任何错误。我认为C#签名是正确的,但我现在不知道调用方法或使用方法 – Karsten 2011-01-12 09:23:37

第一个应该是最容易开始,因为这留给被调查者来确定所需的大小。然而,不知道你应该怎么知道分配的大小。也许是返回值。您始终可以调用GlobalSize()以从HGLOBAL句柄中获取大小。您应该调用GlobalLock()将句柄转换为指针,然后Marshal.CopyMemory()将其复制到byte []中。通过调用GlobalUnlock()和Marshal.FreeHGlobal()来释放内存,将其放入一个finally块中以便不会泄漏。

对于第二个,你应该声明第二个参数为byte [](不是参考)。麻烦的是,你必须预先猜测阵列的大小。失败模式会猜测这个尺寸太小。

第三个需要COM IStream。声明它为System.Runtime.InteropServices.ComTypes.IStream。它的行为很像.NET Stream,你可以调用Seek来寻找开始,阅读来读取数据。

我会为第一个去,最不可能爆炸在你的脸上。

在1: 你应该有二进制数据输出的长度,然后用Marshal.Copy方法如下: 字节[]数据=新的字节[长度]; Marshal.Copy(handle,data,0,length);

For 2 & 3:你有什么问题?