1. ShellExecute function wrapper
- Posted by ryanj May 27, 2016
- 1641 views
Forked from Re: RedyCode 0.9.0 officially released!
I downloaded the latest version, unzipped it, and launched it.
I opened up a project, told it to run the program... and boom. All the windows closed.
Opening it up again didn't give me any hint as to what might have gone wrong.
Uh-oh. What OS are you using? Is there no ex.err anywhere?
I am beginning to suspect a rare problem with the ShellExecute() wrapper, but it's not something that i have been able to reproduce.
From https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx:
Return value
Type: HINSTANCE
If the function succeeds, it returns a value greater than 32. If the function fails, it returns an error value that indicates the cause of the failure. The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows applications. It is not a true HINSTANCE, however. It can be cast only to an int and compared to either 32 or the following error codes below.
What does that mean?
I have
xShellExecute = link_c_func(shell32, "ShellExecuteA", {C_HWND, C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_INT}, C_HWND) public function ShellExecute(atom WinHwnd, sequence filename, sequence parameter, sequence verb = "", sequence workingdir = "") atom result,szapp,szpara,szaction,szdirectory szaction=allocate_string(verb) szapp=allocate_string(filename) szpara=allocate_string(parameter) szdirectory=allocate_string(workingdir) result=c_func(xShellExecute,{WinHwnd,szaction,szapp,szpara,szdirectory,SW_SHOWNORMAL}) free(szaction) free(szpara) free(szapp) if result > 32 then --If the function succeeds, it returns a value greater than 32. return 1 --success else return 0 --failure end if end function
Should it be changed to this? Or does it matter?
xShellExecute = link_c_func(shell32, "ShellExecuteA", {C_HWND, C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_INT}, C_INT)
2. Re: ShellExecute function wrapper
- Posted by ChrisB (moderator) May 27, 2016
- 1553 views
Hi
Not running eu4.05 by any chance, somehow or other?
Cheers
Chris
3. Re: ShellExecute function wrapper
- Posted by ghaberek (admin) May 27, 2016
- 1592 views
From https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153%28v=vs.85%29.aspx:
Return value
Type: HINSTANCE
If the function succeeds, it returns a value greater than 32. If the function fails, it returns an error value that indicates the cause of the failure. The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows applications. It is not a true HINSTANCE, however. It can be cast only to an int and compared to either 32 or the following error codes below.
What does that mean?
That means that in the C code, one might call ShellExecute like this:
// call ShellExecute function HINSTANCE hResult = ShellExecute( handle, _T("open"), _T("my file"), NULL, NULL, SW_SHOWDEFAULT ); // cast result to int value int result = (int)hResult; // check result value if ( result < 32 ) { return 1; } else { return 0; }
One thing to note, is that optional parameters should be NULL, not an empty string. There's a difference. I don't know if this is affecting the behavior of the function call, but it's certainly counter to how the documentation describes the optional paramters.
If the parameter is NULL, that means there is no pointer; you're not pointing to anything. If you pass an empty string, you're still passing a pointer into memory, but its value is of zero length. So in your wrapper code, you should check for empty strings and pass NULL instead of an allocated empty string. Or, what I prefer to do, is accept objects and then allocate strings on the fly and pass atoms as-is.
I have
*snip*
Should it be changed to this? Or does it matter?
xShellExecute = link_c_func(shell32, "ShellExecuteA", {C_HWND, C_POINTER, C_POINTER, C_POINTER, C_POINTER, C_INT}, C_INT)
Using C_INT would be correct since we're expecting a signed value back. AFAIK, C_HWND is unsigned because it's a pointer.
This is how my wrapper for ShellExecute would look. I always try to match the documented API to avoid confusion.
constant xShellExecute = link_c_func( shell32, "ShellExecuteA", {C_HWND,C_POINTER,C_POINTER,C_POINTER,C_POINTER,C_INT}, C_INT ) public function ShellExecute( atom hwnd, object lpOperation, object lpFile, object lpParameters = NULL, object lpDirectory = NULL, atom nShowCmd = SW_SHOWNORMAL ) -- allocate strings if necessary and free them automatically if sequence( lpOperation ) then lpOperation = allocate_string( lpOperation, 1 ) end if if sequence( lpFile ) then lpFile = allocate_string( lpFile, 1 ) end if if sequence( lpParameters ) then lpParameters = allocate_string( lpParameters, 1 ) end if if sequence( lpDirectory ) then lpDirectory = allocate_string( lpDirectory, 1 ) end if return c_func( xShellExecute,{hwnd,lpOperation,lpFile,lpParameters,lpDirectory,SW_nShowCmd} ) end function sequence verb = "open", file = "myfile.txt" if ShellExecute( hwnd, verb, file ) > 32 then -- success else -- failure end if
You had also forgot to free szdirectory.
-Greg
4. Re: ShellExecute function wrapper
- Posted by ryanj May 27, 2016
- 1522 views
I don't know what i was thinking when i wrote that wrapper. I get confused sometimes looking at all those C structures and data types. Thanks, Greg. I'll try your code.
By the way, i borrowed from your Enumerate Fonts wrapper, too.