-1

When I execute system in a thread, nothing happens. Is there a solution?

#include <iostream>
#include <Windows.h>

using namespace std;

void runffplay()
{
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    system(_cmd);
}


CloseHandle(CreateThread(0, 0, (PTHREAD_START_ROUTINE)runffplay, 0, 0, 0));
januw a
  • 2,056
  • 5
  • 18
  • 39
  • 1
    Try this. https://stackoverflow.com/questions/42531/how-do-i-call-createprocess-in-c-to-launch-a-windows-executable – I S Aug 12 '20 at 16:53
  • 4
    Note: `system` is close to the *worst* way you can run another executable from your program. You have very limited control of the environment of the other process and you have very limited ways to capture it's output. And it's a security *nightmare*. Don't use `system`, ever, just don't. – Jesper Juhl Aug 12 '20 at 16:54
  • Have you tried this out with something really simple like starting notepad? If you place a a diagnostic print inside `runffplay`, does diagnostic message print? There are a number of things you can do to help narrow down the problem and either answer your own question or make this into a better question. – user4581301 Aug 12 '20 at 17:17
  • 1
    I'm no Win32 programming guru so I could be missing some small detail, but shouldn't `void runffplay()` be `void runffplay(void *)`? [Looks like I'm a little wrong](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms686736(v=vs.85)). It should be `DWORD runffplay(void *)` – user4581301 Aug 12 '20 at 17:22
  • system() returns a status saying if it failed, and perror() might print any error. Google up the man page! Also, the command or calling shell should print stderr with any error. Maybe use a full path to the command 'ffplay'? In addition to maybe working, it is way more secure! Also, 'ffplay' may need environment, like to find DLLs, other support files. Also, with a trailing & in the cmd, you do not need a thread, unless your functionality needs to know when it finished. – David G. Pickett Aug 12 '20 at 17:29
  • 3
    [Quoiting MS's documentation](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms686736(v=vs.85)): *Do not declare this callback function with a `void` return type and cast the function pointer to `LPTHREAD_START_ROUTINE` when creating the thread. Code that does this is common, but it can crash on 64-bit Windows.* Always good to read the docs to see if they explicitly tell you not to do something you're doing. – user4581301 Aug 12 '20 at 17:30

2 Answers2

2

Your runffplay() function has the wrong signature, so you are going to end up corrupting the thread's call stack. Read the CreateThread() and ThreadProc documentations.

Also, you are not doing any error handling.

Try something more like this instead:

#include <iostream>
#include <cstdlib>
#include <Windows.h>

DWORD WINAPI runffplay(LPVOID)
{
    // instead of system(), consider using exec..(), or CreateProcess() directly...
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    int ret = std::system(_cmd);
    std::cout << "system() returned " << ret << std::endl;
    return 0;
}

HANDLE hThread = CreateThread(NULL, 0, runffplay, NULL, 0, NULL);
if (!hThread) {
    DWORD err = GetLastError();
    std::cerr << "CreateThread() failed with error " << err << std::endl;
}
else {
    ...
    CloseHandle(hThread);
}

Otherwise, use std::thread instead of CreateThread() directly:

#include <iostream>
#include <thread>
#include <cstdlib>

void runffplay()
{
    // instead of system(), consider using exec..(), or CreateProcess() directly...
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    int ret = std::system(_cmd);
    std::cout << "system() returned " << ret << std::endl;
}

std::thread thrd;

try {
    thrd = std::thread(runffplay);
}
catch (const std::system_error &e) {
    std::cerr << "thread failed with error " << e << std::endl;
}

...

if (thrd.joinable()) {
    thrd.join();
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I am yet to understand the significance of running `system` in a thread. Why not simply use `CreateProcess`? – SergeyA Aug 12 '20 at 17:32
  • Well, maybe the thread in the OP's *real* code does more work than just call `system()`. Or maybe the OP wants to wait for the launched process to finish, without blocking the rest of the app. We don't know, so let's not speculate. Launching processes from a worker thread is a perfectly legit operation. – Remy Lebeau Aug 12 '20 at 17:34
0

Use CreateProcess to get the expected result

#include <iostream>
#include <Windows.h>

using namespace std;

HWND ffplayw = 0;

void SetWallpaper()
{
    while (ffplayw == 0)
    {
        ffplayw = FindWindowW(L"SDL_app", 0);
        Sleep(10);
    }
}

int main()
{
    STARTUPINFO info = { sizeof(info) };
    PROCESS_INFORMATION processInfo;
    if (CreateProcess(L"D:\\my-tools\\ffmpeg\\bin\\ffplay.exe",
        (LPWSTR)L" -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"",
        0, 0, 0, 0, 0, 0, &info, &processInfo))
    {
        // WaitForSingleObject(processInfo.hProcess, INFINITE);
        CloseHandle(processInfo.hProcess);
        CloseHandle(processInfo.hThread);
        Sleep(500);
        SetWallpaper();
    }
    return 0;
}

this is okay too:

CreateProcess(
        L"C:\\Windows\\System32\\cmd.exe",
        (LPWSTR)L" /c ffplay -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"",
        0, 0, 0, 0, 0, 0, &info, &processInfo)
januw a
  • 2,056
  • 5
  • 18
  • 39