ShellExecute in _beginthread

804 views Asked by At

I need to run for example:

ShellExecute(NULL, "open", "program.exe", NULL, NULL, SW_HIDE);

as new thread, but I don't know how. I tried this:

HANDLE hThread = (HANDLE) _beginthread(ShellExecute(NULL, "open", "program.exe", NULL, NULL, SW_HIDE), 0, NULL);
WaitForSingleObject( hThread, INFINITE );

but obviously it's wrong and can't be compiled. How should I do this?

1

There are 1 answers

4
conio On

What you tried is indeed obviously wrong, but the question is whether you understand what's wrong with it. _beginthread takes a pointer to function (with a specific prototype and calling convention) as its first parameter.

When you write

HANDLE hThread = (HANDLE) _beginthread(ShellExecute(NULL, "open", "program.exe", NULL, NULL, SW_HIDE), 0, NULL);

you're trying to pass _beginthread the result of calling ShellExecute (in the current thread) which is an HINSTANCE, while _beginthread expects a void( __cdecl *)( void * ) (pointer to a __cdecl function taking one void* parameter and returning void).

Not only your code doesn't work because you're trying to pass an HINSTANCE where a function to pointer is expected, it doesn't make any sense. Have you read the _beginthread documentation? There are examples there. Plural.

What you meant to write is:

HANDLE hThread = (HANDLE) _beginthread(ThreadFunc, 0, NULL);

given:

void __cdecl ThreadFunc(void*) {
    ShellExecute(NULL, "open", "program.exe", NULL, NULL, SW_HIDE);
}

Or, in a more compact and easy to read form:

HANDLE hThread = (HANDLE)
                 _beginthread([](void*) {
                     ShellExecute(NULL, "open", "program.exe", NULL, NULL, SW_HIDE);
                 },
                 0, NULL);

Unless you're doing something beyong what we're seeing here, David'scomment is probably right and you should be using std::thread or std::async.

Also note that taking the result of _beginthread (int contrast to the result of _beginthreadex or CreateThread) in unsafe because it may not be valid, as noted in the documentation. Not only that, but _beginthread's return value isn't really a HANDLE (it is some sore of a handle, but not a HANDLE!), so you can't WaitForSingleObject on it:

The _beginthreadex function gives you more control over how the thread is created than _beginthread does. The _endthreadex function is also more flexible. For example, with _beginthreadex, you can use security information, set the initial state of the thread (running or suspended), and get the thread identifier of the newly created thread. You can also use the thread handle that's returned by _beginthreadex with the synchronization APIs, which you cannot do with _beginthread.

It's safer to use _beginthreadex than _beginthread. If the thread that's generated by _beginthread exits quickly, the handle that's returned to the caller of _beginthread might be invalid or point to another thread. However, the handle that's returned by _beginthreadex has to be closed by the caller of _beginthreadex, so it is guaranteed to be a valid handle if _beginthreadex did not return an error.

Since this thread only calls one function and exits, it almost maximizes the chance of this handle not being valid. And even if it were, you still couldn't use it to WaitForSingleObject.