MFC application crashing in ProcessShellCommand() when file to open specified on command line
我需要解决的问题是,当另一个应用程序正在启动打开文件的应用程序时,如何使用
好的。
我有一个MFC MDI(多文档界面)应用程序,该应用程序由另一个应用程序通过命令行启动,使用
好的。
在调试器中运行,我看到一个错误对话框,标题为" Microsoft Visual C ++运行时库",错误消息为"调试断言失败!"指定src \ mfc \ filelist.cpp的mfc120ud.dll和文件行:221
好的。
此时,我可以附加到应用程序流程,然后单击对话框的"重试"按钮。然后,当我继续时,我看到一个来自未处理异常的Visual Studio错误对话框,该异常似乎是由
好的。
Unhandled exception at 0x76EBC54F in NHPOSLM.exe: Microsoft C++
exception: CInvalidArgException at memory location 0x0014F094.Ok.
如果单击"继续"按钮,这一次我会从src \ mfc \ filelist.cpp行获得另一个"调试断言失败"的提示:234
好的。
为了执行
好的。
一方面,在跳过
好的。
然后我找到了这篇文章,ProcessShellCommand和"视图和框架"窗口,其中指出以下内容:
好的。
The problem is that the code in ProcessShellCommand() opens the
document file before it finishes creating the frame and view windows.
Those windows exist but there is no way to access them because the
frame window pointer is not saved to an app-wide variable until after
the document is open.Ok.
本文提供的解决方案是两次调用
好的。
1 2 3 4 5 6 7 8 9 10 11 12 | CCommandLineInfo cmdInfo; if( !ProcessShellCommand( cmdInfo ) ) return FALSE; ParseCommandLine( cmdInfo ); if( cmdInfo.m_nShellCommand != CCommandLineInfo::FileNew ) { if (!ProcessShellCommand( cmdInfo ) ) return FALSE; } |
我已经在我的应用程序中尝试了这种方法,并且确实确实打开了文档并且似乎可以正确处理所有内容。问题是,虽然这对于MFC应用程序的SDI(单文档界面)类型对于MFC应用程序的MDI(多文档界面)类型有效,但您将看到两个文档窗口,一个是由File New创建的空窗口,另一个是实际的窗口。想要由File Open创建。
好的。
我还发现,如果在异常对话框之后让启动的应用程序继续运行,则使用调试器将其附加到应用程序进程中,然后缓慢地逐步执行,该应用程序将完成所请求的文件。但是,如果不在调试器中,则不会显示启动的应用程序的主窗口。
好的。
因此,似乎存在某种争用条件,环境可以为启动的应用程序完全初始化其运行时环境做好准备。
好的。
有关
好的。
传递给
每个参数一次。
到
我们在
好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views. CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_NEWLAYTYPE, RUNTIME_CLASS(CNewLayoutDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CNewLayoutView/*CLeftView*/)); AddDocTemplate(pDocTemplate); // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // Parse command line for standard shell commands, DDE, file open CLOMCommandLineInfo cmdInfo; /*initialize language identifier to English so we wont have garbage if no language flag is set on teh command line*/ cmdInfo.lang = LANG_ENGLISH; cmdInfo.sublang = SUBLANG_ENGLISH_US; //CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); BOOL success = pMainFrame->ProcessCmdLineLang(cmdInfo.lang, cmdInfo.sublang); if(!success){ AfxMessageBox(IDS_CMDLINE_LANG_NF,MB_OK,0); } // Dispatch commands specified on the command line if (!ProcessShellCommand(cmdInfo)) return FALSE; // The main window has been initialized, so show and update it. pMainFrame->ShowWindow(SW_SHOWNORMAL); pMainFrame->UpdateWindow(); |
我不喜欢两次调用
好的。
最终,我在代码项目Debug Assertion Error Visual Studio 2010中遇到了该帖子,该帖子表明,当文件路径包含星号时,涉及到src \ mfc \ filelist.cpp的类似声明错误也被跟踪到将文件路径添加到"最近文件列表"中。
好的。
当我使用调试器查看
好的。
注意:在调试监视中,字符串中的每个反斜杠实际上都是双反斜杠。因此,要正确地渲染堆栈溢出,我需要添加其他反斜杠,如L" C:\\ Users \\ rchamber \\ Documents \\ ailan_221.dat"所示,但是双反斜杠似乎是调试器用来表示单个反斜杠的东西字符。
好的。
编辑3/23/2016-有关源历史记录的注释
好的。
另外一点信息是此应用程序的源历史记录。 原始应用程序是使用Visual Studio 6.0创建的,然后移至Visual Studio2005。自最初创建以来,
好的。
好。
使用Visual Studio 2013生成新的MFC MDI(多文档界面)应用程序以在遇到启动问题的应用程序与新生成的源代码之间进行比较之后,我有了解决方案。
正确启动与不正确启动之间的主要区别似乎是初始化COM的要求。将以下特定源代码放入正在启动的应用程序的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 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()) { AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; } AfxEnableControlContainer(); // AfxInitRichEdit2() is required to use RichEdit control // AfxInitRichEdit2(); |
虽然Visual Studio 2005编译的应用程序未演示此问题,但我确实希望将Visual Studio 2005和Visual Studio 2013编译的源代码尽可能地保持相似。我在Visual Studio 2005源代码树中进行了相同的源代码更改,并且它在Visual Studio 2005源代码树中也正常工作。
使用Visual Studio 2005并为MDI创建一个空的MFC应用程序会生成类似于上面的源代码。
我正在将桌面应用程序从VC ++更新到Visual Studio 2017,并且在用户尝试通过资源管理器双击打开文件时遇到了相同的问题。
就我而言,我只需要添加以下代码:
1 2 3 4 5 6 7 | // Initialize OLE libraries if (!AfxOleInit()) { AfxMessageBox("Could not open the file! \ Try open CS Setup first and then open the file using the menu \"File->Open...\".", MB_ICONERROR); return FALSE; } |
我在Windows 10中使用Visual Studio 2013和MDI应用程序时遇到了同样的问题。在这里,所提供的两次调用ProcessShellCommand()的解决方案仍然导致崩溃。解决方案是在解释命令行之前创建窗口。那对我有用。
我尝试了CoInitialize()变体,它也可以工作(将其放在下面的代码之前):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // The main window has been initialized, so show and update it. // This needs to be up really before parsing the command line, // so that any FileOpen command has something to render in. pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); // Parse command line for standard shell commands, DDE, file open CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if(!ProcessShellCommand(cmdInfo)) return FALSE; |