Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/146.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用C+调用dll+;来自C的标题#_C#_C++_Marshalling - Fatal编程技术网

C# 用C+调用dll+;来自C的标题#

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

我试图调用一个DLL中的方法,我有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:

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);
        }
    }