【问题标题】:shell32.dll: access violation during GetOpenFileName new threadshell32.dll:GetOpenFileName 新线程期间的访问冲突
【发布时间】:2013-04-02 16:36:42
【问题描述】:

GetOpenFileName 因访问冲突而失败。文件必须在桌面上并且具有长名称。 只有在第一次成功打开文件后才会出现问题。当鼠标光标悬停在文件上时会出现问题,因为工具提示即将显示。

请看下面的答案。我将在下面留下原始问题描述。

迈克 D.

=========================

我正在使用 GetOpenFileName。我有时会在 shell32 内部遇到访问冲突。第一次使用此代码时不会发生违规,通常需要五六次尝试。此外,如果在打开文件窗口弹出后的一两秒内选择一个文件,则不会发生违规。此外,我调试时显示的调用堆栈不包括我的任何代码。就好像某个独立的线程正在醒来做某事。

任何关于我如何调试它的见解都非常感谢!

我制作了一个显示相同行为的“hello”世界应用。然而,它需要更多的尝试才能失败。似乎也必须在失败之前切换目录。

GOFN 是通过专门为此目的创建的线程完成的。以下是来自“hello world”应用程序的代码。

typedef struct 
{
public:
    HWND        hWnd;
    HINSTANCE   hInst;
} def_params, *p_params;

DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid);

void ReadLogFile_DataRecorder (HWND hWnd, HINSTANCE hInst)  // ***************************
{
    static def_params Params;

    Params.hWnd = hWnd;
    Params.hInst = hInst;

    HANDLE T = CreateThread (NULL,0,ReadLogFile_DataRecorderThread,&Params,0,NULL);

    CloseHandle (T);

    return;
}

DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid)   
{
    p_params P = (p_params) pvoid;

    HWND hWnd = P->hWnd;
    HINSTANCE hInst = P->hInst;

    char    ReadLogFileLastDir[256];

//  static def_OpenFileHook Hook;

    OPENFILENAME    ofn;
    char            fn[MAX_PATH]="\0";
    char            filter[32]="Text Files\0*.TXT;\0\0";
    char            title[]="Open IMC Data Recorder Log File";
    char            defext[]="TXT";
    int             status;

// Get File Name

    fn[0] = '\0';
    ReadLogFileLastDir[0] = '\0';

    ZeroMemory(&ofn, sizeof(ofn));

    ofn.lStructSize         = sizeof(ofn);
    ofn.hwndOwner           = hWnd;
    ofn.hInstance           = hInst;
    ofn.hInstance           = (HINSTANCE) GetWindowLong (hWnd, GWL_HINSTANCE);

    ofn.lpstrFilter         = filter;
    ofn.nFilterIndex        = 0;
    ofn.lpstrCustomFilter   = NULL ;
    ofn.nMaxCustFilter      = 0 ;
    ofn.lpstrFile           = fn;
    ofn.nMaxFile            = sizeof(fn);
    ofn.lpstrFileTitle      = NULL;

    if (ReadLogFileLastDir[0] == '\0')
    {
        SHGetSpecialFolderPath (NULL,ReadLogFileLastDir,0x0005,false);
    };
    ofn.lpstrInitialDir = ReadLogFileLastDir;
    ofn.lpstrTitle          = title;
    ofn.Flags               = OFN_FILEMUSTEXIST  | 
                              OFN_PATHMUSTEXIST  | 
                              OFN_EXPLORER       | 
                              // OFN_ENABLETEMPLATE | 
                              OFN_ENABLESIZING   | 
                              // OFN_ENABLEHOOK     |
                              OFN_READONLY;
    ofn.lpstrDefExt         = NULL;
    ofn.lpfnHook            = NULL;         // Hook.DialogHook; // hook routine
    ofn.lCustData           = NULL;          // (long) &Hook;       // data for hook routine
    ofn.lpTemplateName      = NULL;          // MAKEINTRESOURCE(IDD_HOOKFILEOPEN);
    ofn.nFileOffset         = 0 ;
    ofn.nFileExtension      = 0 ;
    ofn.lpstrDefExt         = defext;

    status = GetOpenFileName (&ofn);

    int S;

    S = CommDlgExtendedError();

    return 0;
}

失败时,调用栈是这样的……

SHELL32! 7ca4e035()
SHELL32! 7cb2dc16()
SHELL32! 7cb2dd5a()
SHELL32! 7cb27361()
SHELL32! 7c9f40a3()
BROWSEUI! 75f81b9a()
SHLWAPI! 77f69548()
NTDLL! 7c927545()
NTDLL! 7c927583()
NTDLL! 7c927645()
NTDLL! 7c92761c()
KERNEL32! 7c80b50b()

抱歉,我无法获得这些符号,因为我有一个旧的 Visual C++ :-(

在我看来,当鼠标光标悬停在文件名上时,GOFN 内容即将打开描述文件的弹出窗口时会出现问题。

导致问题的环境有些奇怪。实验表明,必须在 GOFN 窗口中执行以下操作:

  • 在桌面上打开一个文件
  • 将鼠标悬停在长文件名上

如果我这样做两次,它总是失败。我使用的文件名是

IMCLOG_20120323_1658_-_20120324_0653_CST_+DST_E2_2_second.TXT

我用 NOTEPAD 尝试过同样的事情,但出现了同样的问题!

【问题讨论】:

  • 没有符号就没用。
  • 如果您使用的是 Visual Studio,您应该能够通过右键单击堆栈并选择“从 Microsoft 符号服务器加载符号”来获取符号。
  • 我会非常仔细地检查您传入的 OPENFILENAME 结构。特别是与过滤器相关的字段,因为过滤器可以被函数记住并在将来重复使用。
  • 过滤器设置如下 char filter[32]="Text Files\0*.TXT;\0\0";
  • 嘿,你删除了堆栈跟踪。请包含带有符号的堆栈跟踪。

标签: windows shell32 getopenfilename createthread


【解决方案1】:

我发现了许多关于同一问题的报告。例如:

Social.MSDN Problem report
CodeProject question
CodeGuru thread

还有一个 Google 缓存的链接指向已删除的 MS Connect 错误报告。正如您所发现的,问题似乎是桌面中的文件所特有的。

我找到的唯一建议解决方案是在线程开始时调用CoInitializeEx(NULL),并在结束时调用CoUninitialize(),所以值得一试。

另外,GetOpenFileName() 的 MSDN 文档说:

从 Windows Vista 开始,“打开”和“另存为”常用对话框已被“常用项对话框”取代。

因此可能值得完全丢弃GetOpenFileName()

【讨论】:

  • 即使这不是问题的答案,这也是有价值的间接知识。 +1
  • 我希望如此,但作为评论发布太笨拙了。
  • 我没有 CoInitializeEX 但有 CoInitialize。我发现了各种建议使用 #define _WIN32_DCOM 的文章,但这确实为我定义了 CoInitializeEx。我尝试添加 CoInitialize 但问题仍然存在。感谢您的回答,至少我知道问题不是我造成的。 :-)
  • 好的,感谢您的接受 - CoInitialize() 很好,它只是在后来的 SDK 中被弃用了,但它做同样的事情。您必须在调用 GetOpenFileName() 的同一线程中调用它(以防万一)。
  • 我确实从新线程中调用了它,并检查了它是否返回了 S_OK。没有快乐。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多