SharpBITS受尊敬的开源.NET包装器实现(Windows BITS services)无法识别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 instructions。仍然在第二次VerQueryValue(...)调用期间,应用程序崩溃并且毫不犹豫地杀死调试会话。 在崩溃之前只需要一点调试信息:
我通过Windows查看了目标“C:\ Windows \ System32 \ qmgr.dll”文件(BITS的实现)。它说产品版本是7.5.7600.16385。而不是崩溃,这个值应该在verionInfo字符串中返回。有什么建议吗?
答案 0 :(得分:1)
我不知道您的代码是否有问题,但您是否考虑使用FileVersionInfo
类而不是P / Invoke API调用?它更容易使用,更不容易出错...
答案 1 :(得分:1)
大约一年前我看过SharpBITS。我记得当时看到一个Big Bug会使它不适合64位操作系统。不记得确切的错误,可能是一个糟糕的P / Invoke声明。这段代码片段肯定是错误的:
int block2 = Marshal.ReadInt16((IntPtr)((int)subBlock + 2 ));
在x64模式下无法将IntPtr强制转换为int。它必须如下所示:
int block2 = Marshal.ReadInt16((IntPtr)((long)subBlock + 2 ));
或者更好:
int block2 = Marshal.ReadInt16(subBlock, 2);
如果您使用此库来避免这些问题,我强烈建议您强制您的应用以32位模式运行。 Project + Properties,Build选项卡,Platform Target = x86。您可以通知作者here.
答案 2 :(得分:1)
Nobugz的答案确实指出了一个非常有效的问题(大于此问题!),但最终的杀手是一个.NET错误:在x64 .NET实现中,此方案中的编组字符串失败。该错误已在.NET4.0中修复。 Here is the issue reported, as well as Microsoft's answer.
建议的解决方法是检索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);