Sign in to follow this  
cozzie

lpCmdLine, open with and spaces

Recommended Posts

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?

Edited by cozzie

Share this post


Link to post
Share on other sites

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;
}

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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. :)

Edited by Wyrframe

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this