C++ MFC应用程序断言在CRecentFileList处失败::在命令行FileOpen上添加

C++ MFC应用程序断言在CRecentFileList处失败::在命令行FileOpen上添加,c++,visual-studio,visual-studio-2010,com,mfc,C++,Visual Studio,Visual Studio 2010,Com,Mfc,我使用的是VS2010和Windows 7,我的应用程序是SDI共享DLL,从VC6升级而来。安装“我的应用程序”后,如果用户双击已注册的文件类型,应用程序将在MFC功能处崩溃: void CRecentFileList::Add(LPCTSTR lpszPathName, LPCTSTR lpszAppID) { // ... #if (WINVER >= 0x0601) // ... #ifdef UNICODE // ... #endif ENSURE(SUCCEEDED(hr))

我使用的是VS2010和Windows 7,我的应用程序是SDI共享DLL,从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."
// 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;
这是从InitInstance()函数调用的:

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."
// 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。该断言与相同,但原因不同。德国人和我有同样的问题(),但我不能理解谷歌翻译()!!我不认为这是WINVER的问题(),也不想解析我自己的东西(),只要在用户双击文件时打开应用程序即可


感谢您提供的帮助:)

您在代码中插入的注释包含以下答案:

// Crash here: "hr = 0x800401f0 CoInitialize has not been called."
HRESULT
值告诉您需要调用以初始化应用程序线程的COM库

当然,这个信息有点过时了。正如您将在上面链接的文档中看到的,所有新应用程序都应该调用。不过,不用担心:它和它的哥哥做的事情基本上是一样的

如文件“备注”部分所示:

对于使用COM库的每个线程,
CoInitializeEx
必须至少调用一次,并且通常仅调用一次。[…]在调用除
CoGetMalloc
之外的任何库函数之前,需要在线程上初始化COM库,以获取指向标准分配器和内存分配函数的指针。否则,COM函数将返回
CO_E_NOTINITIALIZED

您说您没有使用COM,但这是不正确的。您可能没有明确使用它,但Windows和MFC框架肯定是在“幕后”使用它。所有文件类型注册函数都依赖于COM。VisualStudio2010中的MFC项目向导生成的框架代码会自动插入相应的COM注册代码,但由于您从VC++6升级了现有项目,因此您似乎错过了这一重要步骤

在MFC中,还为调用应用程序的当前单元初始化COM,就像内部一样。确保重写的
InitInstance
函数包含对其中一个函数的调用

例如,在VS 2010向导创建的新MFC项目中,
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;
}

系统可能正在使用COM和ATL,即使您不直接这样做。第一个链接提示VC6和VC10的初始化不同。我将创建一个新的应用程序,并将生成的初始化代码与您拥有的代码进行比较。我打赌有一些新电话!当然有波!但我尝试了:我生成了一个空的MFC项目,获取了新的/不同的代码位,并将它们应用到我的主应用程序中——没有乐趣。我不想把一个20k行的应用程序移动到一个空的MFC项目,因为这!谢谢你的帮助。好的,我明白了。我从未直接从VC6升级到VC10,但我采取了所有的中间步骤,并注意到大部分时间都有变化也许解决方案是将其全部移动到新生成的框架MFC应用程序。我也可以使用新功能…谢谢你,科迪-这真的很有帮助。因此,需要明确的是:在InitInstance()中添加:CoInitializeEx();然后是afxolenit();我发现CoInitializeEx()需要通过在重写的ExitInstance()中调用CoUninitialize()来平衡。这是正确的吗?@Colin:不,实际上不需要同时调用
CoInitializeEx
AfxOleInit
。MFC提供的
AfxOleInit
函数(出于无意义的技术原因,AFX与MFC的含义相同)实际上为您封装了对
CoInitializeEx
的调用,以及一些其他初始化函数。我怀疑,无论出于什么原因,你的VC6应用程序没有调用它(也许它在当时不存在?)。是的,从技术上讲,当你的应用程序退出时,你应该取消COM的初始化,但Windows无论如何都会为你处理。@Colin:我想有人在评论中建议你将VS2010在新项目中开始使用的标准样板代码与你现有的代码进行比较。这应该不会太难,而且可能会解决一些棘手的迁移错误。Cody感谢您继续提供帮助。我已经尝试过使用骨架应用程序中的代码,但没有成功。我再次尝试使用您的代码(CWinApp而不是之前的CWinAppEx),但是我得到了一个断言失败,因为我的代码试图在m_pMainWnd->ShowWindow(SW_SHOW)之前更新UI;已经打过电话了。但这是我的问题,我想不是MFC。再次感谢@科林:嗯,是的。我相信
CWinAppEx
是VisualStudio2008引入的新MFC功能包的一部分。我创建的项目没有使用任何花哨的功能,比如功能区控件。是的,奇怪的是,您应该在
InitInstance
函数中更新UI。UI工作应限于负责显示该UI的窗口类。您不想将该代码放在主应用程序类中。不要忘记MFC仍然鼓励面向对象编程,尽管它偶尔会出现混乱