首先看看InitInstance()函数: BOOL CSomeApp::InitInstance() ...{ Enable3dControls(); LoadStdProfileSettings(); AddDocTemplate(...) ...... ShowWindow(...); m_pMainWnd->DragAcceptFiles(); EnableShellOpen(); RegisterShellFileTypes(TRUE); CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; return TRUE; }
下面对InitInstance中的一些操作及其流程进行分析
1.常规设置
如: SetDialogBkColor() Enable3dControls().. (如果设置了后者,则前者就不必要了) SetRegistryKey(指定注册表键,替代INI文件)
2.LoadStdProfileSettings()
LoadStdProfileSettings 完成最近文件列表功能,在菜单中添加最近的文件作为菜单项过程:
建立一个CRecentFileList从注册表或INI文件中读入最近文件列表;
当菜单建立时,文件列表将添加到菜单中ID_FILE_MRU_FILE*位置;
3.m_pMainWnd->DragAcceptFiles()接收文件拖入
使主窗口能响应文件拖入消息WM_DROPFILES;
当有文件拖入时, 框架窗口的OnDropFiles将处理,以打开这些文件。
void CFrameWnd::OnDropFiles(HDROP hDropInfo) ...{ SetActiveWindow(); // activate us first ! UINT nFiles = ::DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);
CWinApp* pApp = AfxGetApp(); ASSERT(pApp != NULL); for (UINT iFile = 0; iFile < nFiles; iFile++) ...{ TCHAR szFileName[_MAX_PATH]; ::DragQueryFile(hDropInfo, iFile, szFileName, _MAX_PATH); //应用程序打开拖入文档 pApp->OpenDocumentFile(szFileName); } ::DragFinish(hDropInfo); }
4.EnableShellOpen();
为在Windows中使用外壳操作打开文件作准备
void CWinApp::EnableShellOpen() ...{ ASSERT(m_atomApp == NULL && m_atomSystemTopic == NULL); // do once
m_atomApp = ::GlobalAddAtom(m_pszExeName); m_atomSystemTopic = ::GlobalAddAtom(_T("system")); }
5.RegisterShellFileTypes
向系统注册文件类型,以使用外壳操作。
将调用m_pDocManager->RegisterShellFileTypes()
(CDocManager::RegisterShellFileTypes()源码附后)
要点:将所有文档模板的类型,外壳命令等写入注册表
包括type ID、shell/open/ddeexec = [open("%1")]、shell/print/ddeexec = [print("%1")]、shell/printto/ddeexec = [printto("%1","%2","%3","%4")]等等。
6.ProcessShellCommand
处理命令行、外壳命令等
CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE;
①先建立CCommandLineInfo对象
②再将命令行参数等分解到cmdInfo
void CWinApp::ParseCommandLine(CCommandLineInfo& rCmdInfo) ...{ for (int i = 1; i < __argc; i++) ...{ LPCTSTR pszParam = __targv[i]; BOOL bFlag = FALSE; BOOL bLast = ((i + 1) == __argc); if (pszParam[0] == '-' || pszParam[0] == '/') ...{ // remove flag specifier bFlag = TRUE; ++pszParam; } rCmdInfo.ParseParam(pszParam, bFlag, bLast); } } 通过该操作,命令行被转化为cmdInfo; 命令行的意义 app (新建文件) app filename(打开文件) app /p filename(打印文件) app /pt filename printer driver port (用指定的打印机打印) app /dde (运行并接收DDE命令) app /Automation (启动为自动化服务器) app /Embedding (内嵌式运行)
ParseCommandLine后,操作类型(打开、新建、打印..)存放在m_nShellCommand; 文件名存放在m_strFileName......
③处理命令
主要操作:
switch (rCmdInfo.m_nShellCommand) ...{ case CCommandLineInfo::FileNew: OnFileNew().... break; case CCommandLineInfo::FileOpen: OpenDocumentFile(rCmdInfo.m_strFileName).... break; case CCommandLineInfo::FilePrint: case CCommandLineInfo::FilePrintTo: 打开文件,发送ID_FILE_PRINT_DIRECT,返回FALSE值(导致立即程序退出) case CCommandLineInfo::FileDDE: m_nCmdShow = SW_HIDE;(程序被运行,但被隐藏,m_nCmdShow作为ShowWindow的参数) 等等操作 }
附一:CDocManager::RegisterShellFileTypes
void CDocManager::RegisterShellFileTypes(BOOL bCompat) ...{ ASSERT(!m_templateList.IsEmpty()); // must have some doc templates
CString strPathName, strTemp;
AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
POSITION pos = m_templateList.GetHeadPosition(); //针对每种文档模板进行注册 for (int nTemplateIndex = 1; pos != NULL; nTemplateIndex++) ...{ CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(pos);
CString strOpenCommandLine = strPathName; CString strPrintCommandLine = strPathName; CString strPrintToCommandLine = strPathName; CString strDefaultIconCommandLine = strPathName;
if (bCompat) ...{ CString strIconIndex; HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(), strPathName, nTemplateIndex); if (hIcon != NULL) ...{ strIconIndex.Format(_afxIconIndexFmt, nTemplateIndex); DestroyIcon(hIcon); } else ...{ strIconIndex.Format(_afxIconIndexFmt, DEFAULT_ICON_INDEX); } strDefaultIconCommandLine += strIconIndex; }
CString strFilterExt, strFileTypeId, strFileTypeName; if (pTemplate->GetDocString(strFileTypeId, CDocTemplate::regFileTypeId) && !strFileTypeId.IsEmpty()) ...{ // enough info to register it if (!pTemplate->GetDocString(strFileTypeName, CDocTemplate::regFileTypeName)) strFileTypeName = strFileTypeId; // use id name
ASSERT(strFileTypeId.Find(' ') == -1); // no spaces allowed
// first register the type ID of our server if (!_AfxSetRegKey(strFileTypeId, strFileTypeName)) continue; // just skip it
if (bCompat) ...{ // pathDefaultIcon = path,1 strTemp.Format(_afxDefaultIconFmt, (LPCTSTR)strFileTypeId); if (!_AfxSetRegKey(strTemp, strDefaultIconCommandLine)) continue; // just skip it }
// If MDI Application if (!pTemplate->GetDocString(strTemp, CDocTemplate::windowTitle) || strTemp.IsEmpty()) ...{ // pathshellopenddeexec = [open("%1")] strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxDDEExec); if (!_AfxSetRegKey(strTemp, _afxDDEOpen)) continue; // just skip it
if (bCompat) ...{ // pathshellprintddeexec = [print("%1")] strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxDDEExec); if (!_AfxSetRegKey(strTemp, _afxDDEPrint)) continue; // just skip it
// pathshellprinttoddeexec = [printto("%1","%2","%3","%4")] strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxDDEExec); if (!_AfxSetRegKey(strTemp, _afxDDEPrintTo)) continue; // just skip it
// pathshellopencommand = path /dde // pathshellprintcommand = path /dde // pathshellprinttocommand = path /dde strOpenCommandLine += _afxDDEArg; strPrintCommandLine += _afxDDEArg; strPrintToCommandLine += _afxDDEArg; } else ...{ strOpenCommandLine += _afxOpenArg; } } else ...{ // pathshellopencommand = path filename // pathshellprintcommand = path /p filename // pathshellprinttocommand = path /pt filename printer driver port strOpenCommandLine += _afxOpenArg; if (bCompat) ...{ strPrintCommandLine += _afxPrintArg; strPrintToCommandLine += _afxPrintToArg; } }
// pathshellopencommand = path filename strTemp.Format(_afxShellOpenFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxCommand); if (!_AfxSetRegKey(strTemp, strOpenCommandLine)) continue; // just skip it
if (bCompat) ...{ // pathshellprintcommand = path /p filename strTemp.Format(_afxShellPrintFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxCommand); if (!_AfxSetRegKey(strTemp, strPrintCommandLine)) continue; // just skip it
// pathshellprinttocommand = path /pt filename printer driver port strTemp.Format(_afxShellPrintToFmt, (LPCTSTR)strFileTypeId, (LPCTSTR)_afxCommand); if (!_AfxSetRegKey(strTemp, strPrintToCommandLine)) continue; // just skip it }
pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt); if (!strFilterExt.IsEmpty()) ...{ ASSERT(strFilterExt[0] == '.');
LONG lSize = _MAX_PATH * 2; LONG lResult = ::RegQueryValue(HKEY_CLASSES_ROOT, strFilterExt, strTemp.GetBuffer(lSize), &lSize); strTemp.ReleaseBuffer();
if (lResult != ERROR_SUCCESS || strTemp.IsEmpty() || strTemp == strFileTypeId) ...{ // no association for that suffix if (!_AfxSetRegKey(strFilterExt, strFileTypeId)) continue;
if (bCompat) ...{ strTemp.Format(_afxShellNewFmt, (LPCTSTR)strFilterExt); (void)_AfxSetRegKey(strTemp, _afxShellNewValue, _afxShellNewValueName); } } } } } } 附二:CWinApp::ProcessShellCommand BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo) ...{ BOOL bResult = TRUE; switch (rCmdInfo.m_nShellCommand) ...{ case CCommandLineInfo::FileNew: if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL)) OnFileNew(); if (m_pMainWnd == NULL) bResult = FALSE; break;
// If we've been asked to open a file, call OpenDocumentFile()
case CCommandLineInfo::FileOpen: if (!OpenDocumentFile(rCmdInfo.m_strFileName)) bResult = FALSE; break;
// If the user wanted to print, hide our main window and // fire a message to ourselves to start the printing
case CCommandLineInfo::FilePrintTo: case CCommandLineInfo::FilePrint: m_nCmdShow = SW_HIDE; ASSERT(m_pCmdInfo == NULL); OpenDocumentFile(rCmdInfo.m_strFileName); m_pCmdInfo = &rCmdInfo; m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT); m_pCmdInfo = NULL; bResult = FALSE; break;
// If we're doing DDE, hide ourselves
case CCommandLineInfo::FileDDE: m_pCmdInfo = (CCommandLineInfo*)m_nCmdShow; m_nCmdShow = SW_HIDE; break;
// If we've been asked to unregister, unregister and then terminate case CCommandLineInfo::AppUnregister: ...{ UnregisterShellFileTypes(); BOOL bUnregistered = Unregister();
// if you specify /EMBEDDED, we won't make an success/failure box // this use of /EMBEDDED is not related to OLE
if (!rCmdInfo.m_bRunEmbedded) ...{ if (bUnregistered) AfxMessageBox(AFX_IDP_UNREG_DONE); else AfxMessageBox(AFX_IDP_UNREG_FAILURE); } bResult = FALSE; // that's all we do
// If nobody is using it already, we can use it. // We'll flag that we're unregistering and not save our state // on the way out. This new object gets deleted by the // app object destructor.
if (m_pCmdInfo == NULL) ...{ m_pCmdInfo = new CCommandLineInfo; m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister; } } break; } return bResult; }