通过 Win32 检索 dll 版本信息 - VerQueryValue(...) 在 Win7 x64 下崩溃
SharpBITS)。 wikipedia.org/wiki/Background_Intelligent_Transfer_Service" rel="nofollow noreferrer">Windows BITS 服务 无法识别 Win7 x64 下的底层 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 说明 。仍然在第二次 VerQueryValue(...) 调用期间,应用程序崩溃并毫不犹豫地终止调试会话。 在崩溃之前再多一点调试信息:
- spv => “\StringFileInfo\040904B0\ProductVersion”
- 缓冲区=> byte[1900] - 充满二进制数据
- 块1 =>第1033
- 章1200
我通过Windows查看了目标“C:\Windows\System32\qmgr.dll”文件(BITS的实现)。它说产品版本是7.5.7600.16385。该值应该在 versionInfo 字符串中返回,而不是崩溃。有什么建议吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Nobugz 的答案确实指出了一个非常有效的问题(对此非常感谢!),但最终的杀手是 .NET 错误:在 x64 .NET 实现下,这种情况下的编组字符串失败。该错误在.NET4.0中已修复。 以下是报告的问题以及 Microsoft 的答案。
建议的解决方法是检索 IntPtr 而不是字符串作为输出并手动封送字符串。所以最终的代码(包括Nobugz的修复):
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.
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):
我不知道您的代码是否有问题,但是您是否考虑过使用
FileVersionInfo
类而不是 P/Invoke API 调用?它更容易使用并且更不容易出错......I don't know if something's wrong with your code, but have you considered using the
FileVersionInfo
class rather than P/Invoke API calls ? It's easier to use and less error prone...大约一年前我看过 SharpBITS。我记得当时看到一个大错误,这使得它不适合 64 位操作系统。不记得确切的错误,可能是一个错误的 P/Invoke 声明。这段代码肯定是错误的:
IntPtr 不能在 x64 模式下转换为 int。它必须看起来像这样:
或者更好:
如果您使用此库来避免这些问题,我强烈建议您强制您的应用程序以 32 位模式运行。项目 + 属性,构建选项卡,平台目标 = x86。您可以在此处通知作者。
I looked at SharpBITS about a year ago. I remember seeing a Big Bug back then which would make it unsuitable on 64-bit operating systems. Can't remember the exact bug, probably a bad P/Invoke declaration. This code snippet is definitely wrong:
An IntPtr cannot be cast to an int in x64 mode. It must look like this:
Or much better:
I'd strongly recommend you force your app to run in 32-bit mode if you use this library to avoid these problems. Project + Properties, Build tab, Platform Target = x86. You can notify the author here.