【问题标题】:Problem in calling a C++ dll function from C#从 C# 调用 C++ dll 函数时出现问题
【发布时间】:2009-03-29 21:29:48
【问题描述】:

这是我关于 C# 中的河豚问题的第三个线程。尽管事实上我无法在我的应用程序中实现河豚,但我决定将其用作外部 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#代码(函数调用)

-初始化河豚键

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

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

好吧,这不太好。那是我的问题,这就是我向你寻求帮助的原因。

解密时值不同,但如果我在C++源代码中加密和解密,它们是相等的。C++代码是完全一样的,除了没有DLL,因为代码是C++。

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

我找不到线索。我用 C# 中的河豚浪费了我的生命。至少该解决方案应该有效,但它没有 - 为什么?

【问题讨论】:

  • 你浪费了你的妻子? IMO有点过度反应..

标签: c# c++ function dll interop


【解决方案1】:

要补充 jachymko 所说的内容,还请查看 BitConverter 的文档 - 您需要确保以您想要的字节顺序传递密钥和数据。 注意 - 在您之前的帖子中,我使用修改后的 Blowfish.NET 加密器成功加密了数据,并使其与您的 C++ 代码的结果相匹配。

【讨论】:

  • @Dave,感谢您的帮助!你能把修改后的 Blowfish.NET 的源上传到某个地方吗?
  • 是的,我会在某处上传源代码。这是一个 C# 2008 项目和一个 C++ 2008 项目——它们都为我产生了相同的输出。
  • @Dave,谢谢!请在此处粘贴链接,而不是在我的旧线程中。您使用的是我的 C++ 河豚加密,而不是其他的吗?
  • 有效!上帝保佑你戴夫!我误解了你最后的说法,你说我们最后的“修改”造成了一些影响,我认为我必须恢复原来的,所以只有 EncryptBlock 被改变了。我已经成功了,谢谢!
  • 你好戴夫!我遇到了河豚的另一个问题。我无法加密小于 8 字节的字节数组。我做了一些研究,发现为什么它在 C++ Blowfish 中有效,但在 C# 中无效。请查看我的其他线程。 stackoverflow.com/questions/705596/…谢谢!
【解决方案2】:

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

此外,您不需要在这里使用 unsafe 。直接传递 UInt32[] 即可。

【讨论】:

    【解决方案3】:

    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 和一个字节数组,其中存储了一个文本字符串。

    以下 sn-p 显示了如何声明字节数组、传递给 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# 菜鸟)

    HTH

    【讨论】:

      【解决方案4】:

      您可能应该尝试将ref 用于指针,将out 用于通过参数返回数据的函数。让我知道这是否有效。谢谢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多