2016-05-05 5 views
1

私は非常に奇妙なことに気付きました。私はそれがちょうど愚かなエンコーディングエラーだと確信していますが、結果を別々にエンコードしようとするとどちらも役に立ちませんでした。c#StringvuilderでPinvokeを実行すると、同じメソッドで異なる結果が返されます

問題:あなたは私を見ることができるように

私は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 

経由のShell32.dllから機能 "PathYetAnotherMakeUniqueNameを" のPInvokeぼんやりと似た2つの出力しか得られません。私はMarshalAs Attributeを変更しようとしました。あるいはASCII UnicodeやUTF7,8,32などでstringbuildersの内容をエンコードしましたが、出力は変更されませんでした。 MarshalAs(StringBuilderを必要とするいくつかの他のメソッドで動作するようです)を使用しないと、スタックの不均衡例外が発生します。

誰でもこの問題が発生しましたか? 何か助けていただければ幸いです。

は、あなたの入力文字列がLPStrとして整列化されているように思わ事前

+0

これはなぜあなたが 'LoadLibrary'経由でやりたいのですか? – Rotem

+1

StringBuilderの容量をMAX_PATH、260に設定する必要があります。デリゲート宣言が間違っており、すべての文字列がUnicodeです。戻り値を無視しないで、* false *を取得したときに例外をスローします。 LoadLibraryの使用には何の意味もなく、pinvoke marshallerはすでにこれを行っています。 –

答えて

2

で素敵な一日と感謝を持っています。文字列のdefault marshallingUmanagedType.LPTStrです。これはプラットフォームに依存し、LPStrまたはLPWStrのいずれかに解決されます。あなたのプラットフォームではLPStrに解決されていますが、デフォルトのCharSetCharSet.ANSIであり、手動で読み込まれた機能に別のものを指定していない(権限のある確認を歓迎するため)と仮定しています。

明示的に入力パラメータを[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); 

DllImport属性でCharSet = CharSet.Unicodeフィールドは、したがって、あなたのための違いを、このの世話をします。

より直接的な方法は、デリゲートの宣言時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はすでに状況を完全に処理しています。

+0

お返事ありがとうございました!それは完璧に働いた。また、2つのアプローチには実用的な理由はありません。私はそれを新しい方法でさまざまな方法で試しています。 –

関連する問題