3

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

在我们近 10,000 名客户中,只有一 (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(或 -Changing)事件。停止并重新启动程序后,程序中的 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 上,我不得不在他的 PC 上分析问题,从而限制了我检查问题的时间。所以,在实际意义上为他解决了这个问题之后,我留下了一个令人不快的事实,我不知道这怎么会发生,因此我的问题是:任何人都可以在这种黑暗中有所启发吗?

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

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

4

1 回答 1

2

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

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

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

于 2012-10-20T11:52:44.803 回答