带非托管 C++ Unicode DLL 链接到非托管 C++ ANSI DLL 的 C# EXE 崩溃

标签 c# c++ dll unicode ansi

我有一个 C# 可执行文件,它加载到一个 DLL 中,该 DLL 是一个 unicode 非托管 C++ DLL。这个非托管 C++ DLL 还链接到另一个 DLL,一个恰好是 ANSI 的非托管 C++ DLL。

当我运行 C# 可执行文件时,程序最终在 DLL 调用的 ANSI 部分崩溃(我还无法提取异常)。然而,通过简单地将 ANSI DLL 切换为 Unicode,除了存在第三个 DLL(来自另一家公司的 SDK,它对 unicode/ANSI 具有明显的敏感性)之外,一切都可以正常工作,因此如果调用 DLL 则效果最佳采用 ANSI 格式。

因此,我们只有一个非托管 unicode C++ DLL 中有一个可执行调用函数,该 DLL 充当非托管 ANSI C++ DLL 的包装器,而该 DLL 是最终非托管 DLL 的包装器,但我们对此一无所知。

将两个中间 DLL 切换为 unicode 可以纠正崩溃,但第三个独立供应商 DLL 会导致崩溃(但不会因异常而导致灾难性失败,它们只是输出不正确)。我们无法将第一个 DLL 切换为 ANSI,因为我们在 C# 应用程序中使用 Unicode,而这是我们的全面标准。

我不明白二阶 DLL 的敏感性。有人可以帮我解释一下吗?

我使用此类动态链接到 DLL:

static class NativeMethods
        {
            [DllImport("kernel32", SetLastError = true)]
            public static extern bool FreeLibrary(IntPtr hModule);

            [DllImport("kernel32", SetLastError = true)]
            public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

            [DllImport("kernel32", SetLastError = true)]
            public static extern IntPtr LoadLibrary(string dllToLoad);
        }

代表类似于:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
        private delegate int ExampleFunction();

并将 CharSet.Auto 切换为 .Ansi 或 .Unicode 没有任何效果。

带有函数调用等:

m_pDll = NativeMethods.LoadLibrary(@strDLLName);
                if (m_pDll == IntPtr.Zero) this.Close();

                IntPtr pAddressForExampleFunction = NativeMethods.GetProcAddress(m_pDll, "ExampleFunction");
                if (pAddressForExampleFunction == IntPtr.Zero) this.Close();
m_ExampleFunction = (ExampleFunction)Marshal.GetDelegateForFunctionPointer(pAddressForExampleFunction, typeof(ExampleFunction));

带有函数调用:

m_ExampleFunction();

代码中的其他地方。

编辑:

根据要求,C++ EXE 对应项:

在.h文件中,定义为成员:

ExampleFunction pExampleFunction;   

typedef BOOL __declspec(dllimport) (*ExampleFunction)();

pExampleFunction 定义为:

pExampleFunction= (ExampleFunction) ::GetProcAddress(m_hDll,"ExampleFunction");

使用此调用之前:

m_hDll = AfxLoadLibrary(m_DllName);

最佳答案

问题很可能发生在两个非托管 dll 之间,因为它们之间的字符串数据传输不一致。

ANSI/Unicode dll 标志是编译时属性。编译器根据此标志选择类型和函数。对于 Unicode,TCHAR 编译为 wchar_t,对于 ANSI,编译为 char。例如。如果一个 dll 期望获取具有符号长度的 wchar_t*,但实际接收到的值是 char*,则这种差异可能会导致越界问题。这是未定义的行为,可能会导致应用程序崩溃。

此外,许多 Win API 函数有两个版本:xxxW(针对 Unicode)和 xxxA(针对 ANSI)。例如:

#ifdef UNICODE
   #define MessageBox MessageBoxW
#else
   #define MessageBox MessageBoxA
#endif. 

在 C# 端 CharSet属性控制字符串编码(marshal)并确定平台调用如何在 DLL 中查找函数名称。它不会影响非托管 C++ dll 内的进一步字符串操作。方法

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private delegate int ExampleFunction();

没有要编码的字符串,因此 CharSet 不会影响它。如果您在非托管 C++ 端有此方法的两个实现,则可能会有所不同:ExampleFunctionA(适用于 ANSI)和 ExampleFunctionW(适用于 Unicode)。

关于带非托管 C++ Unicode DLL 链接到非托管 C++ ANSI DLL 的 C# EXE 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40248165/

相关文章:

c++ - 检查用户输入时数组元素值是否已经存在

c# - 使用 Windows IoT 在 Raspberry PI 上保存文件

c# - 根据内容的最佳匹配测试创建 WPF UI

c# - 在不使用 String.Split() 的 c# 中拆分字符串的替代方法是什么

c++ - 如何在 C++ 中对静态缓冲区执行字符串格式化?

c++ - 为什么导出的函数在 DLL 中没有正确命名?

c# - 如何从 Web 服务运行 powershell 脚本文件

c++ - OpenMP:同一编译指示上的 nowait 和 reduction 子句

c# - 如何防止dll被加载到其他应用程序中

C# 缺少 MSVCR100.dll