![]() |
|
QA: How can I handle command line parameters in MFC based application?
By Alexander Shargin, March 21, 2001.
QuestionI want to handle command line parameters in my MFC based application. The problem is that MFC based programs have only one copy and when I start my program and it's already running I cannot handle the command like parameters. Let's say instance A of my program is already running. I start instance B with some command line parameters. Instance B checks that instance A is running, sends A foreground and exits. So I cannot access command line parameters of B from instance A. AnswerBy default MFC checks if the application is already running in AfxWinMain function (MFC equivalent of WinMain). If it finds other running instance, it makes its window foreground and terminates. So the command line parameters are lost. MFC allows you yo replace AfxWinMain function with your own to override the default behaviour. Your version of AfxWinMain can pass command line to the first instance by using some IPC mechanism. I suggest using WM_COPYDATA message. After command line is sent AfxWinMain just returns. To implement your own AfxWinMain function follow these steps.
Source codeThis section contains fragments of winmain.cpp, mainfrm.cpp and mainfrm.h files implementing the steps described above. Key parts are marked bold. winmain.cpp:
#include "stdafx.h"
#if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 300)
#define STRIKENUM_MAX 3
typedef struct _FindAppT
{
TCHAR *pzExeName;
HWND hwnd;
}
FindAppT, *pFindAppT;
BOOL CALLBACK FindApplicationWindowProc(HWND hwnd, LPARAM lParam)
{
DWORD dwProcessID;
INT iLen;
TCHAR szTempName[MAX_PATH]=TEXT("\0");
pFindAppT pFindApp=(pFindAppT)lParam;
::GetWindowThreadProcessId(hwnd,&dwProcessID);
if (!dwProcessID)
return TRUE;
iLen=::GetModuleFileName((HMODULE)dwProcessID,szTempName,MAX_PATH);
if (!iLen)
return TRUE;
if (!_tcsicmp(szTempName, pFindApp->pzExeName) )
{
// Check window title to make sure the main window is found.
::GetWindowText(hwnd, szTempName, MAX_PATH);
if (!_tcsicmp(szTempName, _T("CmdLineDemo")) ) // specify your title here.
{
pFindApp->hwnd=hwnd;
return FALSE;
}
}
return TRUE;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// Standard WinMain implementation
// Can be replaced as long as 'AfxWinInit' is called first
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare)
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
#if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 300)
// WinCE: Only one application instance can be run
HANDLE hMuTex;
TCHAR szTempName[MAX_PATH], szExeName[MAX_PATH];
INT i, iValue;
FindAppT findApp;
BOOL bGoAway;
iValue=::GetModuleFileName(NULL,szExeName,MAX_PATH);
_tcscpy(szTempName,szExeName);
for(i = 0; i < iValue; i++)
{
if (szTempName[i]=='\\')
szTempName[i]='/';
}
hMuTex = ::CreateMutex(NULL, FALSE, szTempName);
if (hMuTex!=NULL)
{
if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
bGoAway = FALSE;
memset(&findApp,0,sizeof(FindAppT));
findApp.pzExeName=(TCHAR *)szExeName;
iValue=pThread->GetThreadPriority();
for (i=0; i< STRIKENUM_MAX; i++) {
::EnumWindows(FindApplicationWindowProc,(LPARAM)&findApp);
if (findApp.hwnd)
{
HWND hWnd = (HWND)findApp.hwnd;
::SetForegroundWindow(hWnd);
// Send WM_COPYDATA to the first instance.
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = (_tcslen(lpCmdLine)+1)*sizeof(TCHAR);
cds.lpData = lpCmdLine;
::SendMessage(hWnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
bGoAway=TRUE;
break;
}
// wait for other app to finish starting or stopping
pThread->SetThreadPriority(THREAD_PRIORITY_IDLE);
Sleep(1000);
pThread->SetThreadPriority(iValue);
}
if (bGoAway)
goto InitFailure;
}
}
#endif
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm();
return nReturnCode;
}
/////////////////////////////////////////////////////////////////////////////
mainfrm.h:
class CMainFrame : public CFrameWnd
{
...
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
afx_msg LRESULT OnCopyData(WPARAM, LPARAM);
DECLARE_MESSAGE_MAP()
};
mainfrm.cpp:
...
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
ON_WM_SETFOCUS()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_COPYDATA, OnCopyData)
END_MESSAGE_MAP()
...
LRESULT CMainFrame::OnCopyData(WPARAM wParam, LPARAM lParam)
{
COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam;
// Process command line (contained in (TCHAR*)cds->lpData member).
// In this example we just show command line parameters
// in a message box.
AfxMessageBox((TCHAR*)cds->lpData);
return 0;
}
Related resources:
DiscussDiscuss this article. Here you can write your comments and read comments of other developers. |
|||||||||||||||||||||