通常,在VC++中获取命令行参数的有如下几种方式:
在控制台程序中:
C++运行时库通过入口函数main传递进来的参数int argc 和 char* argv[]。其中第二个参数将一个完整的命令行分割成指向各参数的字符串指针数组,数组中的每一个元素是一个指向参数的字符串指针。其中, argv[0] 指向应用程序名自身。
如果想获得像窗口形式的完整命令行参数CmdLine的话,可以调用API GetCommandLine() 获得。
在窗口程序中:
C++运行时库通过入口函数WinMain传递进来的参数LPTSTR pszCmdLine。pszCmdLine是一个完整的命令行参数,包含应用程序名自身。
如果想获得像控制台形式的被分割的命令行参数指针数组的话。可以使用如下代码获得:
- //C++ code
- pszCmdLineW = GetCommandLineW();
- argv = CommandLineToArgvW(pszCmdLineW, &argc);
- if (argv != NULL) LocalFree(argv);
需要注意的是, CommandLineToArgvW只有Unicode的版本,因此省略第二行的代码,而直接将入口函数中提供的参数lpCmdLine传给 CommandLineToArgvW 可能会存在问题,这取决于项目使用的字符集属性,幸好从 VS2005 开始,项目默认使用的字符集就是 Unicode!
然而,在实际使用命令行参数,其实并不像如上所述那么简单,还有几个不确定的因素会导致获得的命令行参数发生变化。
首先,给出三个测试程序, ConApp 是一个控制台程序,WinApp 是一个窗口程序,这两个程序在内部将获取命令行参数并进行显示,AppCaller是另外一个控制台程序,它将分几次调用 ConApp 和 WinApp ,并为它们传递不同的参数。
测试步骤为:
AppCaller创建ConApp 和 WinApp 子进程,并在控制台上输出传给 ConApp 和 WinApp 的参数,然后等待子进程结束。 ConApp 和 WinApp 显示命令行参数后返回, AppCaller再次调用 ConApp 和 WinAPP 并传递其他参数。
三个程序的代码为:
WinApp:
- //C++ code
- //Win32 project.
- //WinApp.cpp
- #include <Windows.h>
- #include <tchar.h>
- #include <strsafe.h>
- #include <stdarg.h>
- //使用XP风格的控件。
- #if defined _M_IX86
- #pragma comment(linker,"/manifestdependency:/"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'/"")
- #endif
- //函数前导声明。
- HRESULT FormatTextW(WCHAR **, size_t *, LPCWSTR, ...);
- HRESULT AppendTextW(WCHAR **, size_t *, LPCWSTR);
- HRESULT AppendMemHexW(WCHAR **, size_t *, LPBYTE, int);
- int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
- LPTSTR lpCmdLine, int nCmdShow)
- {
- int argc = 0;
- int chLen = 0;
- size_t bufLen = 0;
- HRESULT hr = S_OK;
- LPWSTR pszCmdLineW = NULL;
- LPWSTR *argv = NULL;
- WCHAR szText[1024] = { 0 };
- LPWSTR pCur = NULL;
- pszCmdLineW = GetCommandLineW();
- argv = CommandLineToArgvW(pszCmdLineW, &argc);
- //对命令行参数进行一些格式化,存储到szText中,最后通过MessageBox进行显示。
- bufLen = _countof(szText);
- pCur = szText;
- if (SUCCEEDED(
- hr = FormatTextW(&pCur, &bufLen, L"GetCommandLineW=%s", pszCmdLineW)
- ) && SUCCEEDED(
- hr = AppendMemHexW(&pCur, &bufLen, (LPBYTE)pszCmdLineW,
- wcslen(pszCmdLineW)*sizeof(WCHAR))
- ) && SUCCEEDED(
- hr = AppendTextW(&pCur, &bufLen, L"/r/n")
- ) && SUCCEEDED(
- hr = AppendTextW(&pCur, &bufLen, L"CommandLineToArgvW:/r/n")
- ) && SUCCEEDED(
- hr = FormatTextW(&pCur, &bufLen, L"argc=%d/r/nargv:/r/n", argc)))
- {
- for (int i = 0; i < argc; i++)
- {
- hr = FormatTextW(&pCur, &bufLen, L"[#%u]%s", i, argv[i]);
- if (FAILED(hr)) break;
- hr = AppendMemHexW(&pCur, &bufLen, (LPBYTE)argv[i],
- wcslen(argv[i])*sizeof(WCHAR));
- if (FAILED(hr)) break;
- }
- }
- if (argv != NULL) LocalFree(argv);
- if ((SUCCEEDED(hr)) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
- {
- MessageBoxW(NULL, szText, L"Win App", MB_OK | MB_ICONINFORMATION);
- }
- return 0;
- }
- //格式化文本到缓冲区。
- HRESULT FormatTextW(WCHAR **ppBuf, size_t *pBufLen, LPCWSTR pszFormat, ...)
- {
- va_list argList;
- va_start(argList, pszFormat);
- int chLen = 0;
- HRESULT hr = S_OK;
- hr = StringCchVPrintfExW(*ppBuf, *pBufLen, ppBuf, pBufLen,
- STRSAFE_IGNORE_NULLS, pszFormat, argList);
- va_end(argList);
- return hr;
- }
- //添加文本到缓冲区。
- HRESULT AppendTextW(WCHAR **ppBuf, size_t *pBufLen, LPCWSTR pszText)
- {
- return StringCchCatExW(*ppBuf, *pBufLen, pszText, ppBuf, pBufLen,
- STRSAFE_IGNORE_NULLS);
- }
- //添加16进制形式的内存字节到缓冲区。
- HRESULT AppendMemHexW(WCHAR **ppBuf, size_t *pBufLen, LPBYTE pMem, int cbLen)
- {
- HRESULT hr = S_OK;
- WCHAR sz[512] = { 0 };
- hr = StringCchCatEx(*ppBuf, *pBufLen, L"(", ppBuf, pBufLen,
- STRSAFE_IGNORE_NULLS);
- <