我有一个C#可执行文件加载到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中调用函数,它作为非托管ANSI C ++ 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);
答案 0 :(得分:2)
很可能问题发生在两个非托管dll之间,因为它们之间的字符串数据传输不一致。
ANSI / Unicode dll标志是一个编译时属性。编译器根据此标志选择类型和函数。 Unicode的TCHAR
编译为wchar_t
,ANSI编译为char
。例如。如果一个dll期望获得符号长度为wchar_t*
的实际接收值为char*
,则此类差异可能会导致出界问题。这是未定义的行为,可能导致应用程序崩溃。
许多Win API函数也有两个版本xxxW
用于Unicode,xxxA
用于ANSI。 E.g:
#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif.
在C#side CharSet
属性上控制字符串编组并确定平台调用如何在DLL中查找函数名称。它不会影响非托管C ++ DLL中的进一步字符串操作。方法
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
private delegate int ExampleFunction();
没有要编组的字符串,因此CharSet
不会影响它。如果在非托管C ++端有两个此方法的实现,则可能会有所不同:ANSI的ExampleFunctionA
和Unicode的ExampleFunctionW
。