C# 用C+调用dll+;来自C的标题#
我试图调用一个DLL中的方法,我有C++头。我正在从C#调用dll。输入是字符串,输出是二进制数据。以下三种方法中的任何一种都可能有效,我只是不知道如何让它们一直有效。 C#声明是我做的,所以他们可能不正确 1:我可以得到hGlobal,但我不知道如何从句柄获取数据C# 用C+调用dll+;来自C的标题#,c#,c++,marshalling,C#,C++,Marshalling,我试图调用一个DLL中的方法,我有C++头。我正在从C#调用dll。输入是字符串,输出是二进制数据。以下三种方法中的任何一种都可能有效,我只是不知道如何让它们一直有效。 C#声明是我做的,所以他们可能不正确 1:我可以得到hGlobal,但我不知道如何从句柄获取数据 //CMBT_LL_WINAPI INT DLLPROC LlConvertStringToHGLOBALW(LPCWSTR pszText, _PHGLOBAL phMemory); [DllImport("cmll15.dl
//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:
3:
更新后,这里是我认为我最终会得到的代码
[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);
}
}
对于1:
您应该具有二进制数据输出的长度,然后使用Marshal.Copy方法,如下所示:
字节[]数据=新字节[长度];
Marshal.Copy(句柄,数据,0,长度)
对于2和3:您的问题是什么?第一个应该是最容易开始的,因为这让被叫方自行确定所需的大小。然而,如何知道分配的规模并不明显。可能是返回值。始终可以使用pinvoke GlobalSize()从HGLOBAL句柄获取大小。您应该使用pinvoke GlobalLock()将句柄转换为指针,然后使用Marshal.CopyMemory()将其复制到字节[]。通过调用GlobalUnlock()和Marshal.FreeHGlobal()来释放内存,将其放入finally块中,以防止泄漏 对于第二个参数,您应该将第二个参数声明为byte[](而不是ref)。问题是,您必须预先猜测阵列的大小。故障模式是猜测尺寸太小 第三个需要COM IStream。将其声明为out System.Runtime.InteropServices.ComTypes.IStream。它的行为非常类似于.NET流,您可以从一开始就调用Seek-to-Seek,然后再调用Read-to-Read来读取数据
我会选择第一个,最不可能在你脸上爆炸。你试过编译和运行它们吗?指定问题以便我们理解。如果您已经指定了
CharSet.Unicode
,为什么还要指定ExactSpelling
和EntryPoint
?这些都是多余的。我认为我的问题是把方法从C++翻译成C语言,但是我不知道,我只是展示了它们,这样你就可以发现任何错误。我认为C#签名是正确的,但我现在不知道如何调用方法或使用方法1的给定输出,我在发布后的平均时间内发现了这一点,但我没有长度。大约2,我仍然不知道长度,因此无法将输入设置为N字节。关于3,用pStream=IntPtr.Zero调用方法失败,所以我假设它应该指向一个有效的IStream,我不知道如何创建这样一个IStream,或者我是否在正确的轨道上。1:如果你没有长度,那么答案是不可能的。在C/C++中,任何数组都有一个大小,因此必须设法获得长度。如果dll的代码在您手中,您应该添加一个长度输出参数,否则您应该发现dll中是否有任何函数支持获取数据数组的长度。最后一个机会是,您应该知道字符串文本的编码方式,然后才能知道前面的长度(例如ASCII字符串,然后只传递text.length,或者如果是UTF16,则传递text.length*2)。对于3:请使用IntPtr pStream=Marshal.AllocHGlobal(字节数);大约3:类型是_PISTREAM,我想它需要一个指向IStream对象的指针?我会试试看我能不能用某种方法算出长度我想我有办法了。看来我真的需要打电话给GlobalLock,否则我就不行了。这是源代码,请随意改进。IntPtr h=IntPtr.0_LlConvertStringToHGlobal32(ContentsB,参考h);UIntPtr尺寸=全局尺寸(h);var数组=新字节[(int)大小];IntPtr globalLock=globalLock(h);Marshal.Copy(globalLock,array,0,array.Length);你得好好打扫。GlobalUnlock和Marshall.FreeHGlobal。
[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);
}
}