Valhalla Legends Forums Archive | C/C++ Programming | C++ - Question on Parsing Command line args..

AuthorMessageTime
LordVader
Searched the forum only found one thread close was for java and not quite what im looking for..

Basically I want to create a switch that can fire when the program is started if an argument is passed via command (thru a shortcut to the program).. basically the same as you can do in Onlyers D2Loader..

Im assuming:
*Read the comments
[code]
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
   
   hWndInst = hInstance;

// ---- Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = g_hbrBackground;
wc.lpszClassName = g_szClassMainWnd;
   wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
   wc.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN_ICON));
wc.hIconSm = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAIN_ICON), IMAGE_ICON, 16, 16, 0);

   if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}

/******
Put a switch here to check for a -nogui switch to jump to:
an init main function to bypass window creation
Jump to a function to check if the switch was passed and use that as the switch
*******/

int argResults = FindIntMainArgs();

switch(argResults)
{
case NoGui:
//Jump to a basic winmain init function
break;
default:
{
// Create the Window if no args were sent
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassMainWnd, "Opbot Testing Console", WS_OVERLAPPEDWINDOW, 0, 0, 450, 200, NULL, NULL, hInstance, NULL);
if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
break;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// ---- The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
   TranslateMessage(&Msg);
   DispatchMessage(&Msg);
}
return Msg.wParam;
}
[/code]

Basically:
1. Is that in theory a correct/logical way to go about this?

2. What are the functions in C++ that can catch/interprit arg's passed via command line and maybe a small example.. or link..

Thanks in advanced and hope that code makes since..
Not using dialogs in this instance cause im try'n to learn the api i'm new to C++ :P
September 2, 2004, 12:03 PM
Kp
The command line is available in the parameter lpCmdLine, or you can use GetCommandLineW() / CommandLineToArgvW() to get the system to break it down into component parts for you. CLTAW returns an array of strings, parsed in a manner similar to the argv[] array you should be used to handling. Then it's just a matter of scanning for a trigger string in the array.
September 2, 2004, 2:02 PM
LordVader
Thank's ill play with and do some research on that!
September 2, 2004, 2:08 PM
LordVader
Just noticed lpCmdLine in:
[code]
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
[/code]

+1 Duh for Vader, I didn't even equate it to actually being the actual windows command line heh.

See I am new to C++ =P
But im learning heh.

Thx again for the reply Kp.
September 2, 2004, 2:47 PM
LordVader
Reference on LPSTR lpCmdLine for future readers:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getcommandline.asp

When I get a small sample working ill post that for reference also.
September 2, 2004, 2:57 PM
K
If you need to do more involved parsing (ie, checking for multiple conditions, having positional arguments), my new favorite toy is the boost::program_options library. Unfortunantly program_options hasn't been rolled into a stable boost release yet, but you can check out the latest cvs version to use it.

Here's a small example (this may not compile with the newest cvs version - they're working on changing the syntax before its added to boost.)

[code]
   string in_file_str;
   string out_file_str;
   int line_len;

   options_description desc("Options");
   // interpret first position arg as input file
   // interpret second position arg as output file
   positional_options_description p;
   p.add("input",1);
   p.add("output", 1);


   // --help = -h
   // --input = -i
   // --output = -o
   // --width = -w
   // --number = -n

   desc.add_options()
      ("help,h", "shows this message")
      ("input,i", value<string>(&in_file_str), "set input filename")
      ("output,o", value<string>(&out_file_str)->default_value("out.txt"), "set output filename")
      ("width,w", value<int>(&line_len)->default_value(16), "set line width of output (in characters)")
      ("number,n", "write line offsets to output file");


   variables_map vm;

   try
   {
      store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
      notify(vm);
   }
   catch(exception& ex)
   {
      cout << ex.what() << endl << endl
          << desc << endl;
      return 1;
   }
   // display help
   if (vm.count("help") != 0)
   {
      cout << desc << endl;
      return 0;
   }

   // no input file specified
   if (vm.count("input") == 0)
   {
      cout << "you must specify a file to read." << endl
          << desc << endl;
      return 0;
   }

// ....
[/code]
September 2, 2004, 5:13 PM
LordVader
Thx K, I'll look into it and play around.
September 2, 2004, 11:24 PM
LordVader
Small function for reference that get's command line arguments built from the msdn CommandLineToArgvW reference ..

[code]
void CheckCmdLine()
{
LPWSTR *szArgList;
int nArgs;

// stores the command line includes the following:
// program path/name, and "ALL" command arguments and the total number of arguments is stored into nArgs
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);

//If the command line fails szArgList is empty/null
if(NULL == szArgList)
{
//throw an exception or error here something went wrong.
}

//look for arguments don't include the patch/exe name which is nArgs == 1,
else if(nArgs >=2)
{
//Just an example to catch -gui sent thru the command line
if(!strstr((char *)szArgList," -gui"))
{
// Do stuff for the switch\trigger -gui
}
}
LocalFree(szArgList);
}
[/code]
usage:
[code]
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int mdShow)
{
CheckCmdLine();
return 0;
}
[/code]
*Note this is for win32 applications not thru a console program.
September 8, 2005, 5:59 PM
R.a.B.B.i.T
[code]int main(int argc, char **argv)[/code]Isn't that all he needs?
September 8, 2005, 11:58 PM
Kp
[quote author=LordVader link=topic=8532.msg127412#msg127412 date=1126202386]
Small function for reference that get's command line arguments built from the msdn CommandLineToArgvW reference ..

[code]
void CheckCmdLine()
{
LPWSTR *szArgList;
int nArgs;

// stores the command line includes the following:
// program path/name, and "ALL" command arguments and the total number of arguments is stored into nArgs
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);

//If the command line fails szArgList is empty/null
if(NULL == szArgList)
{
//throw an exception or error here something went wrong.
}

//look for arguments don't include the patch/exe name which is nArgs == 1,
else if(nArgs >=2)
{
//Just an example to catch -gui sent thru the command line
if(!strstr((char *)szArgList," -gui"))
{
// Do stuff for the switch\trigger -gui
}
}
LocalFree(szArgList);
}
[/code]
usage:
[code]
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int mdShow)
{
CheckCmdLine();
return 0;
}
[/code]
*Note this is for win32 applications not thru a console program.[/quote]

Have you tested this?  I can't see that it would work, since you're checking for an ANSI string inside the pointer to your Unicode argument.  Hint: don't just blindly throw in typecasts when you get a compiler warning.
September 9, 2005, 1:24 AM
KkBlazekK
[quote author=rabbit link=topic=8532.msg127455#msg127455 date=1126223883]
[code]int main(int argc, char **argv)[/code]Isn't that all he needs?
[/quote]
Its not a console application hes working on.
September 9, 2005, 1:26 AM
R.a.B.B.i.T
Well then change it to the entry point for whatever he's working on.  I don't see why you would want to grab the command line from a program not running from the command line, it just doesn't make sense.
September 9, 2005, 4:38 AM
Mangix
a lot of programs that have GUIs do this...
September 9, 2005, 5:50 AM
R.a.B.B.i.T
Parameters can be issued run-time from a shortcut or command prompt, and are passed to the program in the same exact way, so changing the entry point to a whatever type of program you're making and keeping the argument declarations should work.
September 9, 2005, 10:34 PM
kamakazie
[quote author=rabbit link=topic=8532.msg127592#msg127592 date=1126305270]
Parameters can be issued run-time from a shortcut or command prompt, and are passed to the program in the same exact way, so changing the entry point to a whatever type of program you're making and keeping the argument declarations should work.
[/quote]

What are you talking about? He is creating a Windows application therefore he needs to use WinMain, not main. main != WinMain.
September 9, 2005, 11:16 PM
LordVader
[quote author=Kp link=topic=8532.msg127463#msg127463 date=1126229071]
[quote author=LordVader link=topic=8532.msg127412#msg127412 date=1126202386]
Small function for reference that get's command line arguments built from the msdn CommandLineToArgvW reference ..

[code]
void CheckCmdLine()
{
LPWSTR *szArgList;
int nArgs;

// stores the command line includes the following:
// program path/name, and "ALL" command arguments and the total number of arguments is stored into nArgs
szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);

//If the command line fails szArgList is empty/null
if(NULL == szArgList)
{
//throw an exception or error here something went wrong.
}

//look for arguments don't include the patch/exe name which is nArgs == 1,
else if(nArgs >=2)
{
//Just an example to catch -gui sent thru the command line
if(!strstr((char *)szArgList," -gui"))
{
// Do stuff for the switch\trigger -gui
}
}
LocalFree(szArgList);
}
[/code]
usage:
[code]
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int mdShow)
{
CheckCmdLine();
return 0;
}
[/code]
*Note this is for win32 applications not thru a console program.[/quote]

Have you tested this?  I can't see that it would work, since you're checking for an ANSI string inside the pointer to your Unicode argument.  Hint: don't just blindly throw in typecasts when you get a compiler warning.
[/quote]

Yes the example I gave does work, about recasting the type in the function I gave..
All im doing is comparing strings to find instances of a given string, not moving/shifting any data:
[code]
if(!strstr((char *)szArgList," -gui")) // szArgList innitially is cast as: LPWSTR *szArgList;
[/code]

Would that actually recast szArgList to char * overall?
Or just for checking within !strstr() ?
Both data container's are null terminated strings.
Curious, what would adverse affects of checking it this way be, even tho one is Unicode vs other as Ansi.
Aren't both null terminated strings resulting in no issues checking this way?

Keep im mind im used to windows, I do not know how other operating systems or compilers would treat that.
But in both visual c++ 6 & 7, it works fine as long for strstr you do:
(char *)szArgList, to compare  LPWSTR *string pointer <- to -> some string to find it in a  instance of a given string...

It did have issues sending LPWSTR data type to strstr, but (char *)szArgList did work with no errors/warnings.

You could probably just use a switch statment for szArgList probably to be a Bit cleaner.
Something like the given example:
Switch Statements on msdn.
Just substitute LPWSTR *buffer for char *buffer in that example..

Haven't tried that yet.

I'm sure their are better cleaner ways to do it, that was just the first thing I tried that did work.
October 17, 2005, 4:56 PM
Kp
[quote author=LordVader link=topic=8532.msg131341#msg131341 date=1129568213]I'm sure their are better cleaner ways to do it, that was just the first thing I tried that did work.[/quote]

When I said it wouldn't work, I meant it in the sense that strstr will never return a match.  Your typecast is causing the compiler to assume you know what you're doing and build it anyway.  As a result, you're looking for the string "-gui" as a substring of the ANSI string composed of the first character of the Unicode argument.  Seeing as one character is definitely shorter than "-gui", strstr will never match.

Also, strstr returns a pointer on success, or NULL on failure.  So your test is asking whether -gui failed to match, not whether it successfully matched.
October 18, 2005, 12:58 AM
LordVader
Ok I see what your saying, and you're correct.. but it does work oddly atleast passing an argument I didn't try passing different arguments other than -gui to see if it worked that way.
Basically I just put a message box within the !strstr if check, with no arguments it launches  with no message, with -gui it found and launched the message box..
Didn't try other arguments tho to see if "anything" passed would trigger the message..

I do see the flaws in it tho with what you said Thx :D

Anyway i'll work on the string searching/matching sometime, the rest tho should work fine.
October 18, 2005, 8:42 AM
Kp
[quote author=LordVader link=topic=8532.msg131438#msg131438 date=1129624949]
Ok I see what your saying, and you're correct.. but it does work oddly atleast passing an argument I didn't try passing different arguments other than -gui to see if it worked that way.
Basically I just put a message box within the !strstr if check, with no arguments it launches  with no message, with -gui it found and launched the message box..
Didn't try other arguments tho to see if "anything" passed would trigger the message..

I do see the flaws in it tho with what you said Thx :D

Anyway i'll work on the string searching/matching sometime, the rest tho should work fine.
[/quote]

This behavior is also entirely consistent with the broken code you posted.  If no arguments are supplied, then it will not hit your erroneous strstr check.  If any arguments are supplied, strstr will run (and fail to match), causing your if test to be true.
October 18, 2005, 11:46 PM

Search