【发布时间】:2012-02-06 09:01:02
【问题描述】:
我正在尝试找到一种在 P/Invoking 之前检测功能是否存在的好方法。比如调用原生的StrCmpLogicalW函数:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
会在一些没有此功能的系统上崩溃。
i don't want to perform version checking,因为这是不好的做法,而且有时可能是错误的(例如,当功能被向后移植时,或者当功能可以被卸载时)。
正确的方法,是检查从shlwapi.dll导出的存在:
private static _StrCmpLogicalW: function(String psz1, String psz2): Integer;
private Boolean _StrCmpLogicalWInitialized;
public int StrCmpLogicalW(String psz1, psz2)
{
if (!_StrCmpLogialInitialized)
{
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
_StrCmpLogicalWInitialized = true;
}
if (_StrCmpLogicalW)
return _StrCmpLogicalW(psz1, psz2)
else
return String.Compare(psz1, psz2, StringComparison.CurrentCultureIgnoreCase);
}
当然,问题在于 C# 不支持函数指针,即:
_StrCmpLogicalW = GetProcedure("shlwapi.dll", "StrCmpLogicalW");
做不到。
所以我正在尝试寻找替代语法来在 .NET 中执行相同的逻辑。到目前为止,我有以下伪代码,但我遇到了阻碍:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
private Boolean IsSupported = false;
private Boolean IsInitialized = false;
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, Export="StrCmpLogicalW", CaseSensitivie=false, SetsLastError=true, IsNative=false, SupportsPeanutMandMs=true)]
private static extern int UnsafeStrCmpLogicalW(string psz1, string psz2);
public int StrCmpLogicalW(string s1, string s2)
{
if (!IsInitialized)
{
//todo: figure out how to loadLibrary in .net
//todo: figure out how to getProcedureAddress in .net
IsSupported = (result from getProcedureAddress is not null);
IsInitialized = true;
}
if (IsSupported)
return UnsafeStrCmpLogicalW(s1, s2);
else
return String.Compare(s1, s2, StringComparison.CurrentCultureIgnoreCase);
}
}
我需要一些帮助。
我想检测是否存在的一些出口的另一个例子是:
dwmapi.dll::DwmIsCompositionEnableddwmapi.dll::DwmExtendFrameIntoClientAreadwmapi.dll::DwmGetColorizationColor-
dwmapi.dll::DwmGetColorizationParameters(未记录1,尚未按名称导出,序号 127) -
dwmapi.dll::127(未记录1,DwmGetColorizationParameters)
1 自 Windows 7 SP1 起
.NET 中必须已经存在用于检查操作系统功能是否存在的设计模式。谁能指出我在 .NET 中执行特征检测的首选方式的示例?
【问题讨论】:
-
.NET Framework 源代码中的设计模式是检查操作系统版本号,但这样做智能正如 Larry Osterman 最终在他的博客文章中总结的那样。我同意 Johann 的解决方案可能更好,但我也是 Win32 人。
LoadLibrary和GetProcAddress对我来说只是有意义。在编写 .NET 代码时,我大部分时间都在编写 P/Invoke 定义。我不确定这是否真的是一件好事。 -
@Cody:我不确定这是否真的是一件好事 - 可能不是,不是。 :-)
-
@CodeGray 你不能依赖版本号。一项功能可能已被追溯移植到操作系统(使版本号错误)。用户也可能没有安装某个功能(使版本号错误)。
-
是的,你可以。它只需要你做你的研究。即使您使用 Johann 的解决方案,您也必须进行足够多的研究才能确定在哪里可以找到您希望调用的 API(即,什么 DLL),这与弄清楚它是否可以是没有太大区别可选安装,或者如果它已被追溯移植到旧操作系统。旧操作系统是已知数量,因为它们在编写代码时已经发布,因此您可以自己检查和验证所有这些。您专门询问了 .NET 中的设计模式,这就是它的作用。
标签: c# pinvoke feature-detection