Tocmai am început acest nou mic proiect al meu în C++ și, deoarece aplicația trebuie să citească și să analizeze argumentele care i-au fost transmise în linia de comandă, m-am gândit că ar fi mai bine să le am pe toate stocate într-un std::std::vector
.
În general, tind să activez suportul pentru caractere largi în aplicațiile pe care le creez, pentru a mă asigura că pot folosi simboluri Unicode; așadar, vectorul va stoca argumentele ca obiecte std::wstring
.
Am testat soluția în Windows (consolă și programe Win32 GUI) și Linux (consolă). Vei găsi mai multe informații în comentarii. Sper că vă poate fi de folos. Mai jos, codul. Eu îl am într-un fișier antet pe care îl includ în sursele CPP.
#include <cstring>
#include <string>
#include <vector>
// APLICAȚII WINDOWS CU CONSOLĂ
#if _CONSOLE
/**
* Obține argumente ale liniei de comandă ca vector în aplicația consolei Windows
*
* Obține numărul de argumente și indicatorul de la punctul principal de intrare wmain
*/
std::vector<std::wstring> cmdArguments(int argc, wchar_t* argv[]) {
return std::vector<std::wstring>(argv, argv + argc);
}
// APLICAȚII WINDOWS CU INTERFAȚĂ GRAFICĂ
#elif _WIN32
#include <shellapi.h>
#include <windows.h>
/**
* Obține argumente ale liniei de comandă ca vector în aplicația Windows
*
* Opțional, se poate trece un indicator la linia de comandă
*/
std::vector<std::wstring> cmdArguments(LPWSTR lpCmdLine = NULL) {
std::vector<std::wstring> arguments;
LPWSTR* szArglist;
int nArgs;
// extrage un indicator la argumentele liniei de comandă utilizând API-ul Shell
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
/**
* Obține argumente ale liniei de comandă ca vector în aplicație Windows / Linux cu consolă
*
* Obține numărul de argumente și indicatorul de la punctul de intrare principal main
*/
std::vector<std::wstring> cmdArguments(int argc, char* argv[]) {
std::vector<std::wstring> arguments;
for (auto i = 0; i < argc; i++) {
// numărul de caractere multiocteți din sursă și rezultat
size_t mbslen = strlen(argv[i]) + 1;
size_t mbolen;
// indicator la argumentul cu caractere largi convertit
wchar_t* wcs = new wchar_t[mbslen];
#ifdef _WIN32
// în Windows putem folosi mbstowcs_s pentru a converti char în wchar_t înainte de a adăuga ca wstring la matrice
mbstowcs_s(&mbolen, wcs, mbslen, argv[i], mbslen - 1);
#else
// în Linux, se calculează lungimea necesară pentru a stoca argv[i] convertit într-un șir de caractere largi
mbslen = mbstowcs(NULL, argv[i], 0);
if (mbslen == (size_t) - 1) {
perror("mbstowcs");
exit(EXIT_FAILURE);
}
// alocă un șir de caractere largi de dimensiunea dorită + 1 pentru caracterul de terminare nul
if (calloc(mbslen + 1, sizeof(*wcs)) == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
// conversia șirului de caractere multioctet din arv[i] într-un șir de caractere largi
if (mbstowcs(wcs, argv[i], mbslen + 1) == (size_t) - 1) {
perror("mbstowcs");
exit(EXIT_FAILURE);
}
#endif
arguments.push_back(std::wstring(wcs));
}
return arguments;
}
Urmează un exemplu al modului în care îl folosesc într-un proiect Win32 (specificarea unui indicator către linia de comandă este opțională)
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;
}
În Linux, am setat și localizarea, pentru a putea folosi caractere speciale
#include <iostream>
#include <locale.h>
#include "arguments.h"
int main(int argc, char* argv[])
{
// setări regionale pentru a permite utilizarea caracterelor UNICODE în linia de comandă
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;
}
Lăsați un mesaj dacă întâmpinați probleme sau dacă aveți îmbunătățiri de sugerat.