所以我注意到一些非常奇怪的事情,我没有解决。我确定这只是一个愚蠢的编码错误,但尝试对结果进行不同的编码并不能帮助我。
问题:
当我Pinvoke函数" PathYetAnotherMakeUniqueName"从Shell32.dll通过DLLImport
[DllImport("shell32.dll", EntryPoint = "PathYetAnotherMakeUniqueName", CharSet = CharSet.Unicode)]
internal static extern bool PathYetAnotherMakeUniqueName2(
System.Text.StringBuilder pszUniqueName,
string pszPath,
string pszShort,
string pszFileSpec);
[...snip...]
System.Text.StringBuilder pszUniqueName = new System.Text.StringBuilder();
PathYetAnotherMakeUniqueName2(pszUniqueName, "Foo", "Bar", "Test");
Console.WriteLine(pszUniqueName); // Output : Foo\Bar
或通过LoadLibrary方法
internal delegate bool dPathYetAnotherMakeUniqueName([MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder pszUniqueName, string pszPath, string pszShort, string pszFileSpec);
static dPathYetAnotherMakeUniqueName PathYetAnotherMakeUniqueName;
[...snip...]
hCurModule = LoadLibrary("shell32.dll");
IntPtr pFunction = GetProcAddress(hCurModule, "PathYetAnotherMakeUniqueName");
PathYetAnotherMakeUniqueName = (dPathYetAnotherMakeUniqueName)Marshal.GetDelegateForFunctionPointer(pFunction,
typeof(dPathYetAnotherMakeUniqueName));
System.Text.StringBuilder pszUniqueName = new System.Text.StringBuilder ();
PathYetAnotherMakeUniqueName(pszUniqueName, "Foo", "Bar", "Test");
Console.WriteLine(pszUniqueName); // output: "?o\?r???o
正如你所看到的,我只得到了两个模糊相似的输出。我尝试更改MarshalAs属性或编码stringbuilders' ASCII Unicode或UTF7,8,32等内容,但输出没有变化。 不使用MarshalAs(它似乎适用于其他一些需要StringBuilder的方法)我得到了一个堆栈不平衡异常。
以前有人遇到过这个问题吗? 非常感谢任何帮助。
度过美好的一天,并提前致谢
答案 0 :(得分:2)
您的输入字符串似乎正在编组为LPStr
。字符串的default marshalling为UmanagedType.LPTStr
,与平台相关,并已解析为LPStr
或LPWStr
。在您的平台上,它被解析为LPStr
,我假设它是因为默认CharSet
是CharSet.ANSI
,并且您没有为手动加载的函数指定不同的({1}}欢迎权威确认)。
将输入参数明确指定为[MarshalAs(UnmanagedType.LPWStr)]
可以解决问题。
internal delegate bool dPathYetAnotherMakeUniqueName(
[MarshalAs(UnmanagedType.LPWStr)]System.Text.StringBuilder pszUniqueName,
[MarshalAs(UnmanagedType.LPWStr)]string pszPath,
[MarshalAs(UnmanagedType.LPWStr)]string pszShort,
[MarshalAs(UnmanagedType.LPWStr)]string pszFileSpec);
CharSet = CharSet.Unicode
属性中的DllImport
字段会为您处理此问题,因此存在差异。
更直接的方法是在声明您的委托时使用UnmanagedFunctionPointer
属性,并指定正确的CharSet
。这更符合您的DllImport
声明。
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet=CharSet.Unicode)]
internal delegate bool dPathYetAnotherMakeUniqueName(
System.Text.StringBuilder pszUniqueName,
string pszPath,
string pszShort,
string pszFileSpec);
更重要的是,在这种情况下似乎没有任何理由使用GetProcAddress
。您事先已经知道了dll的名称,您不需要指定其完整路径,并且您可以保证将找到该DLL并且该函数将在其中找到。DLLImport
已经处理了情况完美。