通过Win32 - VerQueryValue(...)检索dll版本信息在Win7 x64下崩溃 [英] Retrieving dll version info via Win32 - VerQueryValue(...) crashes under Win7 x64

查看:255
本文介绍了通过Win32 - VerQueryValue(...)检索dll版本信息在Win7 x64下崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

的尊重的开源.NET包装器实现( SharpBITS ) /en.wikipedia.org/wiki/Background_Intelligent_Transfer_Servicerel =nofollow noreferrer> Windows BITS服务无法识别Win7 x64下的基本BITS版本。

The respected open source .NET wrapper implementation (SharpBITS) of Windows BITS services fails identifying the underlying BITS version under Win7 x64.

这里是失败的源代码。 NativeMethods是由.NET方法包装的本地Win32调用并通过DllImport属性装饰。

Here is the source code that fails. NativeMethods are native Win32 calls wrapped by .NET methods and decorated via DllImport attribute.

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说明按字母。仍然在第二次VerQueryValue(...)调用期间,应用程序崩溃和杀死调试会话,毫不犹豫。
在崩溃之前只是一些更多的调试信息:

The implementation follows the MSDN instructions by the letter. Still during the second VerQueryValue(...) call, the application crashes and kills the debug session without hesitation. Just a little more debug info right before the crash:


  • spv =>
    \StringFileInfo\ 040904B0\ProductVersion

  • buffer => byte [1900] - 完整的二进制数据

  • block1 => 1033

  • block2 => 1200

  • spv => "\StringFileInfo\040904B0\ProductVersion"
  • buffer => byte[1900] - full with binary data
  • block1 => 1033
  • block2 => 1200

我查看了目标C:\Windows \System32\qmgr.dll 文件(BITS的实现)。它表示产品版本是7.5.7600.16385。而不是崩溃,这个值应该返回verionInfo字符串。任何建议?

I looked at the targeted "C:\Windows\System32\qmgr.dll" file (The implementation of BITS) via Windows. It says that the Product Version is 7.5.7600.16385. Instead of crashing, this value should return in the verionInfo string. Any advice?

推荐答案

Nobugz的答案确实指出了一个非常有效的问题killer是一个.NET错误:在这种情况下处理字符串在x64 .NET实现下失败。该错误在.NET4.0中得到修复。 这是报告的问题,以及Microsoft的回答。

The answer of Nobugz does point out a very valid issue (big thanx for that!), but the final killer was a .NET bug: marshaling strings in this scenario fails under the x64 .NET implementation. The bug is fixed in .NET4.0. Here is the issue reported, as well as Microsoft's answer.

建议的解决方法是检索IntPtr,而不是字符串作为输出,并手动编排字符串。所以最终代码(包括Nobugz的修复):

The recommended workaround is retrieve an IntPtr instead of the string as output and marshaling the string manually. So the final code (including the fix of 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);

这篇关于通过Win32 - VerQueryValue(...)检索dll版本信息在Win7 x64下崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆