从C#调用C ++ DLL函数时出现问题

时间:2009-03-29 21:29:49

标签: c# c++ function dll interop

这是关于C#中的一个河豚问题的第三个主题。虽然我不能在我的应用程序中实现blowfish,但我决定将它用作外部C ++ dll。 请注意我已经尝试过Blowfish.NET和其他任何问题,问题是我正在将代码从C ++转换为C#,而C#代码必须与C ++代码完全相同。

到目前为止:

--->C++ DLL source<---

请注意,导出的函数位于代码

的末尾

C#代码(定义)

    [DllImport("TestDLL.dll", EntryPoint = "Initkey" ,ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void Initkey(byte[] key);

    [DllImport("TestDLL.dll", EntryPoint = "encode", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
    public static unsafe extern void encode(UInt32 *stream);

C#代码(函数调用)

-Initialize blowfish key

UInt32[] keyarray = new UInt32[2];
//some code
Extern.Initkey(Misc.ConvertFromUInt32Array(keyarray));
//
//
//Helper function used to convert a UInt32 array into Byte array.
public static byte[] ConvertFromUInt32Array(UInt32[] array)
{
    List<byte> results = new List<byte>();
    foreach (UInt32 value in array)
    {
        byte[] converted = BitConverter.GetBytes(value);
        results.AddRange(converted);
    }
    return results.ToArray();
}

- 编码数据。

            UInt32[] keyarray2 = new UInt32[2];
            //some code
            unsafe
            {
                fixed (UInt32* LPBYTE = keyarray2)
                {
                    Extern.encode(LPBYTE);
                }
            }

在使用Encode函数覆盖keyarray2之后,我通过解密来检查C ++代码中的值,以确保一切正常。

嗯,这不行。这是我的问题,这就是我要求你帮助的原因。

当我解密它们时,值是不同的,但如果我加密它们并在C ++源代码中解密它们,它们是相同的.C ++代码完全相同,只是因为代码是在C ++中没有DLL。 / p>

可能是因为Initialize函数。我几个月前读过C ++中的数组作为Pointers传递。我不相信它,但即便如此 - 这可能是问题吗?

我找不到线索。我用C#中的那条河豚浪费了我的生命。至少该解决方案应该有效,但事实并非如此 - 为什么?

4 个答案:

答案 0 :(得分:1)

您是否意识到正在初始化一个在Initkey函数返回时被销毁的临时实例?您应该将整个事物组合在一个函数中,或者在堆上创建cBlowfish并返回指向C#代码的指针(它可以将其视为不透明的IntPtr)。

此外,您不需要在这里使用不安全的。直接传递UInt32 []。

答案 1 :(得分:1)

要添加到jachymko所说的内容,还要检查BitConverter的文档 - 您需要确保按照预期的字节顺序传递密钥和数据。 注意 - 从您之前的线程,我使用修改后的Blowfish.NET加密器成功加密数据,并使其与您的C ++代码的结果相匹配。

答案 2 :(得分:0)

C和C ++中的数组作为指针传递。 C#中数组的语义包括一个额外的间接层。您的C#程序(可能)传递保存数据地址的变量的地址。

我最近努力将C#中的字节数组传递给C函数,并且必须在两个方向上编组数据。对我来说,你的代码就是这样做并不明显。

比解释更好,我将提供一个具体的例子:

//extern "C" LIBEXIFWRAPPER_API void findEXIFtagValue( void * load, unsigned int tagID, char* buf, int bufLen );
[DllImport("libexif-wrapper.dll")]
unsafe public static extern IntPtr findEXIFtagValue([MarshalAs(UnmanagedType.SysUInt)]IntPtr load, int tagID, [MarshalAs(UnmanagedType.SysUInt)]IntPtr buf, int bufLen); 

此函数接受指向不透明数据的指针,一个int和一个字节数组,用于存储文本字符串。

以下代码段显示了如何声明字节数组,传递给C函数以及提取的结果:

const int tagBuffer = 1024;
IntPtr buf = Marshal.AllocHGlobal(tagBuffer);

findEXIFtagValue(loader, (int)ExifTag.EXIF_TAG_DATE_TIME, buf, tagBuffer);
string s = Marshal.PtrToStringAnsi(buf);

请注意,参数在原型中编组并再次编组以检索结果。

这对我来说都不是特别明显。似乎IntPtr是void *的C#等价物,除了我必须使用SysUInt来管理(C)void *。指向字节数组的指针被封送为SysUInt。

(来自C#noob)

HTH

答案 3 :(得分:0)

可能应该尝试使用ref作为指针,使用out作为通过参数返回数据的函数。如果有效,请告诉我。感谢。