0

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?

Lukasz Re
  • 79
  • 1
  • 11
  • 3
    Pretty unlikely that you need a new thread. `ShellExecute` is asynchronous. It will return immediately. It won't block on the other process. If you are starting a new process, `CreateProcess` is usually preferable anyway. If you want to do it in a new thread, create a function with this signature `void( __cdecl *start_address )( void * )` that calls `ShellExecute`. Then pass that function to `_beginthread`. If you are using C++ then it would make more sense to use `std::thread` surely. – David Heffernan Jan 18 '17 at 15:33
  • 2
    The only reason why you'd ever want to run `ShellExecute` (or `ShellExecuteEx` really) in its own thread is, because you need to initialize COM on that thread and it may collide with the calling thread's apartment. However, you aren't even attempting to do that, so it's completely unclear, why you believe that you need to spin up a thread, and then block for it to finish executing. This doesn't implement anything useful. – IInspectable Jan 18 '17 at 15:48

1 Answers1

3

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.

Community
  • 1
  • 1
conio
  • 3,681
  • 1
  • 20
  • 34
  • Both the `ThreadFunc` definition as well as the lambda function are missing the respective calling convention. What's more, this answer doesn't even question the necessity for spinning up a new thread, even though there is absolutely nothing in the question indicating, that this were beneficial. – IInspectable Jan 18 '17 at 23:13
  • [`_cdecl` is the default calling convention in MSVC](https://msdn.microsoft.com/en-us/library/zkwh89ks.aspx). I considrerd this to be common knowledge,but perhaps I was wrong. Though this wasn't states explicitly to be case, since OP is using a function from the MSVC CRT, I deduced him to be using MSVC or a compatible compiler and toolchain. – conio Jan 18 '17 at 23:42
  • The answer doesn't question the necessity of creating a new thread for three reasons: (1) An **answer** is not the place for this, but rather the **comments** area, that indeed was already used for it; (2) It is irrelevant to the answer, and (3) OP stated that he "need[s] to run for **example**: `ShellExecute(...)`". For example. Perhaps he really wants to run something else. Perhaps he runs various tasks, this being only one of them. That was an **example**. The generalized question, **disregarding the example**, was how to call a function on a new thread. This I answered. – conio Jan 18 '17 at 23:43
  • 1
    @IInspectable: At least in VC++, and probably other compilers, when a captureless lambda is implicitly converted to a function pointer, it takes on whatever calling convention is needed (the compiler generates code for all calling conventions, and then the linker eliminates any unused code). See [What's the default calling convention of a C++ lambda function?](http://stackoverflow.com/questions/14845706/) and [Non-capturing C++ lambdas can be converted to a pointer to function, but what about the calling convention?](https://blogs.msdn.microsoft.com/oldnewthing/20150220-00/?p=44623) – Remy Lebeau Jan 19 '17 at 02:13