lpCmdLine, open with and spaces

Started by
3 comments, last by Wyrframe 7 years, 8 months ago

Hi all,

I've tried to create a simple win32 application that takes a filename as input parameter, using lpCmdLine:


int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{
	std::string inputCmdLine = lpCmdLine;

	std::wstring inputFilename;
	inputFilename.append(inputCmdLine.begin(), inputCmdLine.end());

	std::ifstream exists(inputFilename);
	if(exists) 
	{

// do stuff

This kinda works, when I place the release executable in a folder and from that same folder I drag a file to the executable.

But there are 2 situations where the filename is not found/ is not interpreted correctly:

- use a input file with spaces in it's filename or it's folder where it's stored

- use the 'open with' function in windows explorer

In both these cases the result is that the string gets a " (quote) at the beginning and at the end, causing the filename not to be processed anymore.

I've tried to go through to the string and if I encounter a " (quote) remove it from the string, for example:

"test.dds" becomes test.dds.

But I still get the same symptons, aka not working.

Do you have any idea how to tackle this?

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Advertisement

The standard windows function to parse the command line into the more usual argc and argv format is CommandLineToArgvW().

It does handle quoted arguments.

Great, it works after some playing around. Thanks!.

For who's interested, this is my 1st pipeline tool for my engine :)

It simply returns the DDS surface format by dragging a file to this executable, or you can use 'open with' on DDS files.

Very handy because most lightweight DDS texture viewers either don't show the surface format or they're bound to the d3d days.


int WINAPI WinMain(HINSTANCE hInstance,
				   HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,
				   int nCmdShow)
{
	// TESTING THE COMMAND LINE ARGUMENTS
	LPWSTR *szArgList;
	int nArgs = 0;

	szArgList = CommandLineToArgvW(GetCommandLineW(), &nArgs);
	if(szArgList == NULL)
	{
		MessageBox(NULL, L"No input file!", L"Error", MB_OK);
		return 0;
	}
	
	// store individual arguments to strings
	char temp[255];
	std::string *argTexts = new std::string[nArgs];

	for(int i=0;i<nArgs;i++)
	{
		temp[0] = '\0';
		sprintf_s(temp, "%ws", szArgList[i]);
		argTexts[i] = temp;
	}
	free(szArgList);

	// CONTINUE (argument 0 = application exe, argument 1 = dragged file/ open with file)
	std::string inputCmdLine = argTexts[1];
	std::wstring inputFilename;
	inputFilename.append(inputCmdLine.begin(), inputCmdLine.end());

	std::ifstream exists(inputFilename);
	if(exists) 
	{
		if(CreateD3d11Device())
		{
			DXGI_FORMAT DDSformat = DirectX::GetDDSSurfaceFormat(d3dDevice, inputFilename.c_str());
			MessageBox(NULL, DXGI_formats[DDSformat].c_str(), inputFilename.c_str(), MB_OK);
		}
	}
	else
	{
		MessageBox(NULL, L"File doesn't exist", inputFilename.c_str(), MB_OK);
	}

	ReleaseCOM(d3dDevice);
	ReleaseCOM(d3dImmediateContext);

	return 1;
}

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

You have one small bug there - you're not freeing the memory correctly.

From the documentation:

CommandLineToArgvW allocates a block of contiguous memory for pointers to the argument strings, and for the argument strings themselves; the calling application must free the memory used by the argument list when it is no longer needed. To free the memory, use a single call to the LocalFree function.

Some other very important bugs and logical slips:

  • All entries of the array 'argTexts' are going to be pointers to the same 255-char buffer 'temp', which will contain only the last argument on the command line.
  • 'temp' has a finite size and you're not checking the size of the source string first, so you should use snprintf and provide the size of the destination buffer, instead of sprintf (really, I don't know why modern compilers even let you get away with using sprintf without really loud warnings that can be promoted to errors with -Wstrict).
  • I can't find any documentation describing how sprintf (rendering to char sequences) handles conversion from wide-char strings (as per your %ws format code). Why not just call inputFileName.append(szArgList[1]), instead of using two separate char-formatted intermediates ('char* temp' and 'std::string inputCmdLine')?
  • CommandLineToArgvW only returns null if there's some critical command-line parsing failure, like unclosed quotes or passing in a null pointer. You should check the value of nArgs to determine if at least one command-line parameter was passed or not, not the nullity of szArgList.
  • If the file doesn't exist, you still try to release a Direct3D context that you never created. If that variable is uninitialized or ReleaseCOM() doesn't like getting passed null pointers, you're in for a world of hurt there.

Hope that all helps you analyze your code more critically. Even if you think this is a tiny, one-off, personal-use-only tool that doesn't need quality and reliability, these are bad habits to let yourself develop. :)

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

This topic is closed to new replies.

Advertisement