0

尊敬されているWindowsBITSサービスのオープンソース.NETラッパー実装(SharpBITS)は、 Win7x64での基になるBITSバージョンの識別に失敗します。

失敗するソースコードは次のとおりです。NativeMethodsは、.NETメソッドによってラップされ、DllImport属性を介して装飾されたネイティブWin32呼び出しです。

private static BitsVersion GetBitsVersion()
    {
        try
        {
            string fileName = Path.Combine(
                     System.Environment.SystemDirectory, "qmgr.dll");
            int handle = 0;
            int size = NativeMethods.GetFileVersionInfoSize(fileName, 
                                                            out handle);
            if (size == 0) return BitsVersion.Bits0_0;
            byte[] buffer = new byte[size];
            if (!NativeMethods.GetFileVersionInfo(fileName, 
                                                  handle, 
                                                  size, 
                                                  buffer))
            {
                return BitsVersion.Bits0_0;
            }
            IntPtr subBlock = IntPtr.Zero;
            uint len = 0;
            if (!NativeMethods.VerQueryValue(buffer,
                              @"\VarFileInfo\Translation", 
                              out subBlock, 
                              out len))
            {
                return BitsVersion.Bits0_0;
            }

            int block1 = Marshal.ReadInt16(subBlock);
            int block2 = Marshal.ReadInt16((IntPtr)((int)subBlock + 2 ));
            string spv = string.Format(
                 @"\StringFileInfo\{0:X4}{1:X4}\ProductVersion", 
                 block1, 
                 block2);

            string versionInfo;
            if (!NativeMethods.VerQueryValue(buffer, 
                                             spv, 
                                             out versionInfo, 
                                             out len))
            {
                return BitsVersion.Bits0_0;
            }
...

実装は、MSDNの指示に従って文字で行われます。それでも2回目のVerQueryValue(...)呼び出し中に、アプリケーションはクラッシュし、ためらうことなくデバッグセッションを強制終了します。クラッシュ直前のもう少しデバッグ情報:

  • spv => "\ StringFileInfo \ 040904B0 \ ProductVersion"
  • buffer =>byte[1900]-バイナリデータでいっぱい
  • block1 => 1033
  • block2 => 1200

ターゲットの「C:\ Windows \ System32 \ qmgr.dll」ファイル(BITSの実装)をWindows経由で調べました。製品バージョンは7.5.7600.16385であると書かれています。クラッシュする代わりに、この値はverionInfo文字列で返される必要があります。何かアドバイス?

4

3 に答える 3

2

Nobugzの答えは非常に有効な問題を指摘していますが(そのことに感謝します!)、最後のキラーは.NETのバグでした。このシナリオでの文字列のマーシャリングは、x64.NETの実装では失敗します。バグは.NET4.0で修正されています。報告された問題とMicrosoftの回答は次のとおりです。

推奨される回避策は、出力として文字列の代わりにIntPtrを取得し、文字列を手動でマーシャリングすることです。したがって、最終的なコード(Nobugzの修正を含む):

int block1 = Marshal.ReadInt16(subBlock);
int block2 = Marshal.ReadInt16(subBlock, 2);
string spv = string.Format(@"\StringFileInfo\{0:X4}{1:X4}\ProductVersion", 
                             block1, block2);

IntPtr versionInfoPtr;
if (!NativeMethods.VerQueryValue(buffer, spv, out versionInfoPtr, out len))
{
     return BitsVersion.Bits0_0;
}
string versionInfo = Marshal.PtrToStringAuto(versionInfoPtr);
于 2010-03-17T07:54:08.960 に答える
1

コードに問題があるかどうかはわかりませんが、FileVersionInfoP / Invoke API呼び出しではなくクラスを使用することを検討しましたか?使いやすく、エラーが発生しにくい...

于 2010-02-17T19:16:35.317 に答える
1

私は約1年前にSharpBITSを見ました。当時、64ビットオペレーティングシステムには適さない大きなバグを見たのを覚えています。正確なバグ、おそらく悪いP/Invoke宣言を思い出せません。このコードスニペットは間違いなく間違っています:

int block2 = Marshal.ReadInt16((IntPtr)((int)subBlock + 2 ));

IntPtrは、x64モードではintにキャストできません。次のようになります。

int block2 = Marshal.ReadInt16((IntPtr)((long)subBlock + 2 ));

またははるかに良い:

int block2 = Marshal.ReadInt16(subBlock, 2); 

これらの問題を回避するためにこのライブラリを使用する場合は、アプリを強制的に32ビットモードで実行することを強くお勧めします。プロジェクト+プロパティ、ビルドタブ、プラットフォームターゲット=x86。ここで作者に通知できます。

于 2010-02-17T19:49:34.583 に答える