Remember the main function from our standard C programs or the win32 console programs. It used to have two arguments argc and argv as follows
int main(int argc, char * argv[]) ...
These parameters helped us send command line parameters to our programs. ‘argc’ would hold the number of arguments passed and argv would be an array of the parameters passed. But when we are doing a GUI based win32 application in visual studio, we would use the WinMain function as our entry point. This function doesnt have an argc or an argv argument. So how do we pass command line parameters to Windows programs, and how do we access them in our programs.
lpCmdLine argument
One solution is the WinMain function itself. Let us look at the typical declaration of WinMain
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)..
As we can see in the declaration, we have an argument called lpCmdLine of type LPSTR (char *). This variable stores the entire command line minus the name of the program. For eg if we had a program called ‘test.exe’ and if we called it as
test.exe Some arguments here
The variable lpCmdLine would hold the value “Some arguments here”. This is one way of accessing command line parameters, although not as helpful as the classic argc and argv. We would have to write the code to parse the lpCmdLine variable ourselves, thus increasing the complexity of our program. Also, as we can see lpCmdLine is actually an ANSI string and thus would not work with Unicode characters being passed at commandline.
GetCommandLine()
Another method is to use GetCommandLine() api. This function returns the entire command line, i.e. it includes the program name (which could include the absolute path) and also all the parameters in a single string. This is similar to directly accessing lpCmdLine, but the advantage is that it is mapped to either the ANSI GetCommandLineA() function or the unicode GetCommandLineW() function depending on your projects settings. This solves the problem of unicode input thru command line, but it still doesnt provide a count of arguments neither the arguments as seperate variables like argv.
CommandLineToArgvW()
The last method that I am going to discuss is CommandLineToArgvW This function only works with the Unicode/Wide character set and there seem to be no CommandLineToArgvA ANSI equivalent function. The prototype is as follows
LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine, int *pNumArgs)
This function comes closest to the simplicity of argc and argv, or rather it gives us access to our argc and argv in the windows program. As we can see the function accepts two arguments, one is a unicode commandline string which needs to be parsed, the second is a pointer to an int variable. The function stores the number of arguments in this variable when it returns.
The function returns an array of strings, which is similar to argv. Lets look at an example.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
{
LPWSTR *szArgList;
int argCount;
szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);
if (szArgList == NULL)
{
MessageBox(NULL, L"Unable to parse command line", L"Error", MB_OK);
return 10;
}
for(int i = 0; i < argCount; i++)
{
MessageBox(NULL, szArgList[i], L"Arglist contents", MB_OK);
}
LocalFree(szArgList);
return 0;
}
As we can see above by using this function, we get the commandline as the number of arguments(argc) and a list of strings (argv). The only thing to remember here is that, the function allocates a block of memory for the argument list. We have to manually delete this memory whenever we are done with it, or we will have a leaking application.
EDIT: Variables __argc and __argv
As pointed below by anonymous, Microsoft compiler provides us with the variables __argc and __argv. These variables are automatically populated at runtime by windows. The variables are available in two flavors, the ASCII version and the Unicode version. __argv is the ascii version, whereas __wargv is the unicode version. To use them we have to include stdlib.h, which is automatically included whenever you include windows.h. To let the project setting decide which version of the variable to use, we can access __targv, by including TCHAR.h.
This method is the simplest of them all, but the caveat is that we have to link to the VC++ runtime library i.e. msvcrt.dll (which we would for almost 99% of windows programs).
I hope this helps everyone, would love to hear everyone’s comments regarding the same.

This is a useful and excellent share. Will definitely share it with people I know.
thanks a lot for information! hello from 2023 🙂 !!!!
Hi, pretty old post, however, should be noted, “__wargv” works when “wWinMain” is used (in case of “WinMain”, the __wargv results in undefined behavior – unknown memory).
Thanks, super helpful guide. Glad you took the time to share all this research!
Very helpful tutorial. Thanks.
I made it worked perfectly on Visual Studio 2015.
The code not work perfectly, the perfect solution I’ve found is in this post:
http://stackoverflow.com/a/42048224/4612829
Thanks that was really helpful!
PS. The behavior of CommandLineToArgvW I mentioned before is standard, it’s indicated in the MS documentation. So it’s not an error, that’s how they wrote it. Not very helpful if you ask me, but then it’s easy to circumvent this by checking lpCmdLine as I said.
Actually, I haven’t checked argc and argv any more, it’s simpler to check lpCmdLine instead, see if it’s empty (that is, “”).
Hello
Thanks for this article, looks like it’s rather helpful.
But I noticed a catch. If there are no arguments, the CommandLineToArgvW function will return 1 as the no. of arguments, and have one string in the array which will be the name of the program. On the contrary, if there are arguments, then the function returns their number ant the string array, without including the name of the program. This is rather unhelpful when the program can have 0 or more arguments (and, if one wants to write a solid program, one must always consider the case that it was called without arguments, possibly in error).
Anyway, I thought I’d let you know about this behavior. At least that’s what it did in my setting. You could check to see it does this to you too and update your article to reflect this.
Vlad
PS. I haven’t checked the argc, argv variables, I’m about to do it now and I’ll post shortly what I’ll find.
Didn’t know about __argv and __argc. Thanks for adding this.
Thank you. This is exactly what I am looking for.
I am frequently to blogging and i certainly appreciate your content. The post has definitely peaks my interest. I’m going to bookmark your website and keep checking for new facts.
cheap jordans online http://www.jerseyspxjf.350.com/testpage.htm
Hello sir.
I have problem running winmain on visual studio 2010 with directx sdk (june 2010)
Can you help me to solve this?
please watch this:
Thanks. We appreciate your publishing this. We are using Native C++ in Visual Studio 10 for a testbed for Senselock dongles. In the end we opted for the __argc / __argv option as this is simplest by far.
Thanks for your clear and helpful explanation!
Stunning quest there. What happened after?
Thanks!
Thank , for the clear explaination.
This was crystal clear. Thanks. It also soothed my frayed nerves.
Great post, thank you for the info!
I’ll immediately seize your rss feed as I can’t in finding your e-mail subscription
link or newsletter service. Do you have any? Please allow me know so that I may
subscribe. Thanks.
i need a help about running my .exe with command line arguments seperately.
i want to call this exe in another program using create process. Need Help..
Perfect and clear information which i have gained from this site.. Try to enlarge this site with more and more needed information for the developers
!! GREAT POST !!!
Effective, very simple to understand…..
🙂
great post!
Btw, still a small typo in the sample code:
for(int i = 0; i < argCount; i++;)
Should be:
for(int i = 0; i < argCount; i++)
Thank you for pointing out the silliness of my for loop. I have updated the sample code. I always wondered what ‘argh’ was talking about almost a year ago.
Hey there,
This is the BEST post I’ve seen online which discusses the various options you have to parse command line arguments.
Thank you for taking your time to write this up!
ps. There is a small mistake on the code sample.
“for(int i = 0; i++; i < argCount)"
should be
"for(int i = 0; i < argCount; i++)"
Thanx for the infos!
Maybe you should check your for…
Thanks a lot for the information, I will update the article accordingly.
There’s an even easier way: use the __argv variable.
hmm.. informative 🙂