I just started this new little project of mine in C++, and because the application needs to read and parse the arguments passed to it in the command line, I thought it would be better to have all of them stored inside a std::vector
.
I tend to enable wide char support in the applications I create, to make sure they can use Unicode characters, so the vector will store the arguments as std::wstring
objects.
I tested the solution in Windows (console and Win32 GUI programs) and Linux (console). You will get more information in the comments. I hope you will find it useful. Here is the code. I have it in a header file that I include in my CPP source.
#include <cstring>
#include <string>
#include <vector>
// WINDOWS CONSOLE APPS
#if _CONSOLE
/**
* Get command line arguments as vector in Windows console application
*
* Get arguments count and pointer from wmain entry point
*/
std::vector<std::wstring> cmdArguments(int argc, wchar_t* argv[]) {
return std::vector<std::wstring>(argv, argv + argc);
}
// WINDOWS GUI APPS
#elif _WIN32
#include <shellapi.h>
#include <windows.h>
/**
* Get command line arguments as vector in Windows application
*
* Optionally, you can pass a pointer to the command line
*/
std::vector<std::wstring> cmdArguments(LPWSTR lpCmdLine = NULL) {
std::vector<std::wstring> arguments;
LPWSTR* szArglist;
int nArgs;
// retrieve a pointer to the command line arguments using the Shell API
szArglist = CommandLineToArgvW(lpCmdLine != NULL ? lpCmdLine : GetCommandLineW(), &nArgs);
if (szArglist != NULL) {
for (auto i = 0; i < nArgs; i++) arguments.push_back(szArglist[i]);
}
LocalFree(szArglist);
return arguments;
}
#endif
/**
* Get command line arguments as vector in Windows/Linux console application
*
* Get arguments count and pointer from main entry point
*/
std::vector<std::wstring> cmdArguments(int argc, char* argv[]) {
std::vector<std::wstring> arguments;
for (auto i = 0; i < argc; i++) {
// number of multibyte characters in source and result
size_t mbslen = strlen(argv[i]) + 1;
size_t mbolen;
// pointer to converted wide character argument
wchar_t* wcs = new wchar_t[mbslen];
#ifdef _WIN32
// in Windows we can use mbstowcs_s to convert char to wchar_t before adding as wstring to array
mbstowcs_s(&mbolen, wcs, mbslen, argv[i], mbslen - 1);
#else
// in Linux, calculate the length required to hold argv[i] converted to a wide character string
mbslen = mbstowcs(NULL, argv[i], 0);
if (mbslen == (size_t) - 1) {
perror("mbstowcs");
exit(EXIT_FAILURE);
}
// allocate wide character string of the desired size + 1 for terminating null wide character
if (calloc(mbslen + 1, sizeof(*wcs)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
// convert the multibyte character string in argv[i] to a wide character string
if (mbstowcs(wcs, argv[i], mbslen + 1) == (size_t) - 1) {
perror("mbstowcs");
exit(EXIT_FAILURE);
}
#endif
arguments.push_back(std::wstring(wcs));
}
return arguments;
}
The following is an example of how I use it inside a Win32 project (specifying a pointer to the command line is optional)
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// std::vector<std::wstring> arguments = cmdArguments();
std::vector<std::wstring> arguments = cmdArguments(lpCmdLine);
for (const std::wstring& i : arguments) {
MessageBox(
NULL,
(LPCWSTR)i.c_str(),
(LPCWSTR)L"Argument",
MB_ICONINFORMATION | MB_OK
);
wprintf(_T("%ls"), i.c_str());
}
return 0;
}
In Linux, I also set the locale, in order to be able to use special characters
#include <iostream>
#include <locale.h>
#include "arguments.h"
int main(int argc, char* argv[])
{
// set locale to allow usage of UNICODE characters in command-line
if (setlocale(LC_ALL, "en_US.UTF-8") == NULL) {
perror("setlocale");
exit(EXIT_FAILURE);
}
std::vector<std::wstring> arguments = cmdArguments(argc, argv);
for (const std::wstring& wArg : arguments) {
std::wcout << wArg.c_str() << "\n";
}
return 0;
}
Let me know if you have any problems or if you have some improvements to suggest.