为什么SHGetFileInfo会改变(当前)文化?

时间:2012-10-20 08:44:45

标签: vb.net file dropbox

上下文:目前在VisualStudio2012中开发/维护的程序,用VB(.NET)编写,目标是Framework v3.5。我们的大多数客户都使用荷兰语Windows安装,并且大多数客户的区域设置都设置为荷兰语(nl-NL),这意味着。 (句号)用于分组,(逗号)用作小数分隔符。

在近10,000名客户中,只有ONE(1)遇到问题,我们认为原因是调用SHGetFileInfo来获取文件的(小)图标。代码中的相关陈述:

  Private Declare Unicode Function SHGetFileInfo Lib "Shell32.dll" Alias "SHGetFileInfoW" (pszPath As String, dwFileAttributes As UInteger, ByRef psfi As SHFILEINFO, cbSizeFileInfo As UInteger, uFlags As UInteger) As IntPtr

Dim result As IntPtr = SHGetFileInfo(pszPath, dwFileAttributes, psfi, cbSizeFileInfo, uFlags)

我们评估了 - 在该客户的特定PC上 - 在(第一次)调用SHGetFileInfo之前,System.Globalization.CultureInfo.CurrentCulture是(nl-NL),如预期的那样,但是在调用之后,CurrentCulture已经切换到(en-US),这显然在其他地方引起了问题。

在此时暂停代码并检查配置面板,区域设置仍然是荷兰语(nl-NL)。此外,代码中未捕获任何SystemEvents.UserPreferenceChanged(或-Cnging)事件。停止并重新启动程序后,程序中的CurrentCulture再次成为荷兰语(nl-NL) - 直到第一个SHGetFileInfo调用。

在实际意义上,我们通过在必要时重置CurrentCulture解决了这个问题:

  Private Declare Unicode Function SHGetFileInfo0 Lib "Shell32.dll" Alias "SHGetFileInfoW" (pszPath As String, dwFileAttributes As UInteger, ByRef psfi As SHFILEINFO, cbSizeFileInfo As UInteger, uFlags As UInteger) As IntPtr


  Private Shared Function SHGetFileInfo(pszPath As String, dwFileAttributes As UInteger, ByRef psfi As SHFILEINFO, cbSizeFileInfo As UInteger, uFlags As UInteger) As IntPtr

    Dim ciBefore As System.Globalization.CultureInfo = Application.CurrentCulture

    Dim result As IntPtr = SHGetFileInfo0(pszPath, dwFileAttributes, psfi, cbSizeFileInfo, uFlags)

    Dim ciAfter As System.Globalization.CultureInfo = Application.CurrentCulture
    If (ciAfter.Name <> ciAfter.Name) OrElse (ciBefore IsNot ciAfter) Then
      Application.CurrentCulture = ciBefore
    End If

    Return result
  End Function

由于问题只出现在那个特定的客户PC上,我不得不在他的电脑上分析问题,限制我检查时间。因此,在实际意义上为他解决问题之后,我留下了一个令人不快的事实,即我不知道这是怎么发生的,因此,我的问题是:在这黑暗中,任何人都能解开一些光吗?

其他信息:客户直到一个月前才出现此问题。最近他开始使用(并且可能安装)DropBox和BoxSync。我不知道这些的内部工作原理,但由于它们“使用文件”并且它们的安装或多或少与出现的问题一致,我确实怀疑可能存在连接。

我希望我已经充分说明了这个问题,但如果需要更多信息,我会很乐意尝试提供这个。任何帮助将不胜感激。提前感谢任何建议。

1 个答案:

答案 0 :(得分:2)

线程的CurrentCulture属性是一个非托管属性。本机代码可以调用SetThreadLocale()来更改它。因此,当你对一个非托管函数进行调整时,为什么文化会发生变化并不完全是神秘的。

此外,SHGetFileInfo()之类的shell函数受shell扩展行为的影响。在野外有很多它们并不经常造成这样的问题。调用SetThreadLocale()是一种修复格式问题的便捷方法,而不是恢复语言环境是一个严重错误,特别是在shell扩展中,因为它在其他进程的上下文中运行。

不要通过更改代码来解决此问题,告诉客户修理他的机器。最好的方法是运行SysInternals'AutoRuns utility。 Explorer选项卡显示所有已安装的shell扩展的列表。禁用Publisher列中没有“Microsoft”的所有内容。注销+登录以使其生效。如果他不能没有这些扩展,那么他可以逐个重新启用它们来找到麻烦制造者。