在运行时更改DllImportAttribute的CharSet字段

时间:2013-03-16 15:25:14

标签: c# reflection unicode pinvoke dllimport

我要做的是能够使用托管代码中的相同方法针对本机DLL的两个版本进行编译。

例如,这将是我的原生方法签名:

__declspec(dllexport) void MyClass::NativeFoo(const TCHAR* txt)

它编译为接受一个版本中的char*和另一个版本中的wchar*

pInvoke签名如下所示:

[DllImport("Native.dll")]
private static extern void NativeFoo(string txt);

为了能够控制pInvoke调用使用的CharSet,我使用以下方法:

internal static void SetUnicodeMode(bool state)
{
    MethodInfo m = typeof(ManagedFoo).GetMethod("NativeFoo", BindingFlags.NonPublic | BindingFlags.Static);
    object[] atts = m.GetCustomAttributes(typeof(DllImportAttribute), false);
    DllImportAttribute dllatt = (atts[0] as DllImportAttribute);
    dllatt.CharSet = state ? CharSet.Unicode : CharSet.Ansi;
}

我在托管程序集启动时调用此方法(此时我知道是否需要使用unicode或mbcs)。

该方法不会抛出任何异常,但它也不会更改pInvoke调用使用的CharSet。我做错了什么?

1 个答案:

答案 0 :(得分:2)

这不起作用。 CLR将创建自己的[DllAttribute]实例,它不会使用你的。用于属性构造函数参数的值存储在程序集元数据中,您无法更改该数据。

前进的唯一合理方法是使用具有不同名称的两个声明。使用属性的EntryPoint属性将它们映射到相同的导出函数。否则你不清楚用什么触发器来选择一个触发器,实际的DLL当然也必须是不同的。这是非常不寻常的,当您使用不同的编译器设置重建DLL时,TCHAR只是一个不同类型的字符。特别是UNICODE和_UNICODE #defines。没有任何可以想象的理由仍然使用8位字符,或TCHAR,这是上个世纪。这里有一个健全性检查。