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()
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)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、shellopenddeexec = [open("%1")]、shellprintddeexec = [print("%1")]、shellprinttoddeexec = [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......
③处理命令
主要操作:
(本文来源于图老师网站,更多请访问http://m.tulaoshi.com/bianchengyuyan/)switch (rCmdInfo.m_nShellCommand)
{
case CCommandLineInf:FileNew:
OnFileNew()....
break;
case CCommandLineInf:FileOpen:
OpenDocumentFile(rCmdInfo.m_strFileName)....
break;
case CCommandLineInf:FilePrint:
case CCommandLineInf:FilePrintT
打开文件,发送ID_FILE_PRINT_DIRECT,返回FALSE值(导致立即程序退出)
case CCommandLineInf: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 CCommandLineInf: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 CCommandLineInf: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 CCommandLineInf:FilePrintT
case CCommandLineInf: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 CCommandLineInf:FileDDE:
m_pCmdInfo = (CCommandLineInfo*)m_nCmdShow;
m_nCmdShow = SW_HIDE;
break;
// If we've been asked to unregister, unregister and then terminate
case CCommandLineInf: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 = CCommandLineInf:AppUnregister;
}
}
break;
}
return bResult;
}