Ошибка приложения MFC в CRecentFileList :: Add в командной строке FileOpen - PullRequest
2 голосов
/ 09 июля 2011

Я использую VS2010 и Windows 7, и мое приложение представляет собой общую библиотеку SDI, обновленную с VC6.После установки моего приложения, если пользователь дважды щелкает по зарегистрированному типу файла, происходит сбой приложения в функции MFC:

void CRecentFileList::Add(LPCTSTR lpszPathName, LPCTSTR lpszAppID)
{
 // ...
#if (WINVER >= 0x0601)
// ...
#ifdef UNICODE
// ...
#endif
ENSURE(SUCCEEDED(hr));    // Crash here: "hr = 0x800401f0 CoInitialize has not been called."

Это вызывается из функции InitInstance ():

// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);

//CString str = cmdInfo.m_strFileName + '\n';
//MessageBox(NULL,str, "MyApp", MB_OK|MB_ICONWARNING);

// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
    return FALSE;

Выбранный пользователем файл правильно пропущен (как я проверил с помощью MessageBox).

Кажется, что hr = 0x800401f0 - это проблема COM ( здесь ), но я неиспользуя COM или ATL.Утверждение такое же, как this , но по другой причине.У немцев была та же проблема, что и у меня ( здесь ), но я не могу понять перевод Google ( здесь ) !!Я не думаю, что это проблема WINVER ( здесь ), и я не хочу анализировать свои собственные вещи ( как этот ), просто открывайте приложение, когда пользователь дважды щелкаетфайл.

Спасибо за любую помощь, которую вы можете предложить:)

1 Ответ

2 голосов
/ 09 июля 2011

Комментарий, который вы вставили в свой код, содержит ответ:

// Crash here: "hr = 0x800401f0 CoInitialize has not been called."

Значение HRESULT говорит о том, что вам нужно вызвать функцию CoInitialize , чтобы инициализировать библиотеку COM для потока вашего приложения.

Конечно, сообщение немного устарело. Как вы увидите в вышеупомянутой документации, все новые приложения должны вместо этого вызывать функцию CoInitializeEx . Не беспокойтесь: он делает то же самое, что и его старший брат.

Как указано в разделе «Замечания» документации:

CoInitializeEx должен вызываться как минимум один раз и обычно вызывается только один раз для каждого потока, использующего библиотеку COM. [. , , ] Вам необходимо инициализировать библиотеку COM в потоке перед вызовом любой из функций библиотеки, кроме CoGetMalloc, чтобы получить указатель на стандартный распределитель и функции выделения памяти. В противном случае функция COM вернет CO_E_NOTINITIALIZED.

Вы говорите, что не используете COM, но это неверно. Возможно, вы не используете его явно, но Windows и инфраструктура MFC определенно используют его "за кулисами". Все функции регистрации типов файлов зависят от COM. Скелетный код, созданный мастером проекта MFC в Visual Studio 2010, автоматически вставил соответствующий код регистрации COM, но, поскольку вы обновили существующий проект с VC ++ 6, вы, похоже, пропустили этот важный шаг.

В MFC функция AfxOleInit также инициализирует COM для текущей квартиры вызывающего приложения, так же как и функция OleInitialize внутренне. Убедитесь, что ваша переопределенная функция InitInstance содержит вызов одной из этих функций.

Например, в новом новом проекте MFC, созданном мастером VS 2010, функция InitInstance выглядит примерно так:

BOOL CTestApp::InitInstance()
{
    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    CWinApp::InitInstance();

    // Initialize OLE libraries
    if (!AfxOleInit())                   // ** MAKE SURE THAT YOU CALL THIS!! **
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }

    AfxEnableControlContainer();

    // . . . 
    // a bunch more boring initialization stuff...

    // The one and only window has been initialized, so show and update it
    pFrame->ShowWindow(SW_SHOW);
    pFrame->UpdateWindow();
    return TRUE;
}
...