Search code examples
c++windowsnetwork-programmingwindows-messages

Cannot get program to process WM_POWERBROADCAST message


I have a program that I want to automatically terminate on a WM_POWERBROADCAST message. For some reason, however, it is not terminating when I cause the computer to sleep. The program should have more than enough time to respond to this call, but I don't think the program is processing the message at all. I believe this mainly because the program doesn't terminate when the computer resumes, either, and the message should at least be in the window's queue.

What am I doing wrong that is causing my program not to be able to process this message?

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_POWERBROADCAST:
        DestroyWindow(hWnd);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_CLOSE:
        return 0;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //Set title of program
    //SetConsoleTitleA("Star");
    //FreeConsole();

    //Change the current directory of the program back to the appropriate folder
    wchar_t* UserProf;
    SHGetKnownFolderPath(FOLDERID_Profile, 0, NULL, &UserProf);
    const wchar_t* EndProf = L"\\AppData\\UserUpdates";
    wcsncat(UserProf, EndProf, 23);
    wstring ws(UserProf);
    string wstr(ws.begin(), ws.end());
    //cout << wstr << endl;
    SetCurrentDirectoryA(wstr.c_str());

    WNDCLASSW WindowClass{CS_NOCLOSE, WindowProc, 0, 0, hInstance, NULL, LoadCursor(nullptr, IDC_ARROW), NULL, NULL, L"chakra"};

    RegisterClass(&WindowClass);

    HWND hWnd = CreateWindow(L"chakra", L"star", WS_POPUP, 0, 0, 10, 10, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, SW_HIDE);

    string ipAddress = "10.0.0.201"; //IP address of my computer on local network
    int port = 13777;
Hunter:
    WSAData data;
    WORD ver = MAKEWORD(2, 2);
    int wsResult = WSAStartup(ver, &data);
    if (wsResult != 0) {
        //cerr << "Can't start Winsock, Err#" << wsResult << endl;
        return 0;
    }

    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET) {
        //cerr << "Can't create socket" << endl;
        return 0;
    }

    sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(port);
    inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
    int connCounter = 0;

    //Constantly attempts to connect to server
    do {
        int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
        if (connResult == SOCKET_ERROR) {
            connCounter = 0;
            closesocket(sock);
            WSACleanup();
            goto Hunter;
        }
        else {
            connCounter = 1;
        }
    } while (connCounter == 0);

    char buf[1024]; //Where message from server will be stored
    char* pbuf{ buf };

    //Things to compare

    const char* CreateAccount = "create"; //Server tells client to make IG account
    const char* CheckStatus = "check"; //Client tells server if account is running or not
    const char* Info = "info"; //Client sends Username and Password of account to server
    const char* Run = "run"; //Tells client to start running the account
    const char* Kill = "kill"; //Kills program on client for around a month
    const char* Settings = "settings"; //Server sets settings for account to run on
    string TryAgain = "#13 Not a valid input, either type [check] to check if the account is running, type [create] to create new account, or type [info] for account information\n";
    string accInfoSuccess = "#777 You have successfully entered the information for the account (^.^)\n";
    string settingsInfoSuccess = "#777 You have successfully set the settings for this account (^.^)\n";
    string accInfoProblem = "#13 There was a problem in either saving the information to this account or the account creation program. Type [create] and try again (T.T)\n";
    string settingsInfoProblem = "#13 There was a problem in saving the account settings. Type [settings] and try again (T.T)\n";
    string accRun = "#777 The account is currently running! ~(^.^)~\n";
    string accNoRun = "#13 Sorry the account isn't running, type [run] to run the account (O.o)\n";
    string accNoInfo = "#13 There is no info for an account that can be run. Type [create] to make information (\".\")\n";
    string accRunErr = "#13 There is a problem with opening the main bot program, try again. If this problem persists, there is an issue clientside V(T.T)V\n";

    int loopCounter = 0;


    //int on = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)TRUE, sizeof(TRUE));

    MSG Msg = { 0 };

    do {
        ZeroMemory(buf, 1024);

        u_long block = 0;
        ioctlsocket(sock, FIONBIO, &block);
        DWORD timeout = 500;
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
        //setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));

        int bytesReceived = recv(sock, buf, 1024, 0);
        if (bytesReceived > 0) {
            //Check to see if it equals one of the strings above
            if (strstr(pbuf, CreateAccount)) {
                //Run program to create account
                int accountSuccess;
                accountSuccess = accountCreation(sock);
                if (accountSuccess == 0) {
                    int sendResult = send(sock, accInfoSuccess.c_str(), accInfoSuccess.size() + 1, 0);

                }
                else {
                    int sendResult = send(sock, accInfoProblem.c_str(), accInfoProblem.size() + 1, 0);
                }
            }
            else if (strstr(pbuf, Settings)) {
                int settingsSuccess;
                settingsSuccess = settingsCreation(sock);
                if (settingsSuccess == 0) {
                    int sendResult = send(sock, settingsInfoSuccess.c_str(), settingsInfoSuccess.size() + 1, 0);

                }
                else {
                    int sendResult = send(sock, settingsInfoProblem.c_str(), settingsInfoProblem.size() + 1, 0);
                }
            }
            else if (strstr(pbuf, CheckStatus)) {
                //Check to see if program that runs account is running
                int accountSuccess = isRunning();
                if (accountSuccess == 0) {
                    int sendResult = send(sock, accRun.c_str(), accRun.size() + 1, 0);

                }
                else if (accountSuccess == 1){
                    int sendResult = send(sock, accNoRun.c_str(), accNoRun.size() + 1, 0);

                }
                else {
                    int sendResult = send(sock, accNoInfo.c_str(), accNoInfo.size() + 1, 0);

                }
            }
            else if (strstr(pbuf, Info)) {
                //Read text file containing account info and send to server
                int infoChecker = checkInfo(sock);
                if (infoChecker != 0) {
                    int sendResult = send(sock, accNoInfo.c_str(), accNoInfo.size() + 1, 0);

                }
            }
            else if (strstr(pbuf, Run)) {
                //Runs the account running program
                int running = runProg();
                if (running == 0) {
                    int sendResult = send(sock, accRun.c_str(), accRun.size() + 1, 0);
                }
                else {
                    int sendResult = send(sock, accRunErr.c_str(), accRunErr.size() + 1, 0);
                }
            }
            else if (strstr(pbuf, Kill)) {
                //Kills this program
                WSACleanup();
                return 0;
            }
            else {
                //Send back to server that the wrong thing was inputted
                int sendResult = send(sock, TryAgain.c_str(), TryAgain.size() + 1, 0);
                ZeroMemory(buf, 1024);
                loopCounter = 0;
            }
        }
        else {
            //Check to make sure bot is running
            int vroom = isRunning();
            if (vroom == 1) {
                //runProg();
                loopCounter = 0;
            }
            else {
                loopCounter = 0;
            }
        }

        if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }

    } while (loopCounter == 0);

    WSACleanup();
    return 0; 
}

Solution

  • There are a TON of problems with the code shown, but lets start with the most important one that is affecting your message issue - all of that thread-blocking socket code DOES NOT belong inside your WinMain() at all, let alone inside your message loop itself. That is why your handling of window messages, like WM_POWERBROADCAST, is running so slow.

    You need to restructure your code. Either:

    • move the socket code to a worker thread, and let it block that thread all it wants.

    • use asynchronous socket I/O (via WSAAsyncSelect(), etc) that you can process inside of your WindowProc. Or use overlapped I/O. Either way, no threading or blocking operations are needed.

    Whatever you do, DO NOT block WinMain()'s message loop.

    That being said, other problems with your code include:

    • SHGetKnownFolderPath(..., &UserProf); wcsncat(UserProf, EndProf, 23); is undefined behavior. SHGetKnownFolderPath() does not allocate enough memory for you to append anything onto. You need to allocate another buffer large enough to copy UserProf into and append EndProf into. Or, simply convert UserProf to a std::wstring first and then append EndProf onto the end of that (either way, don't forget to free UserProf when you are done with it - you are currently leaking it).

    • you should not be adding your custom UserUpdates subfolder directly to the user's AppData folder itself. Use FOLDERID_LocalAppData/Low, FOLDERID_RoamingAppData, or FOLDERID_ProgramData instead to get a more appropriate folder to add your things to.

    • string wstr(ws.begin(), ws.end()); is not the correct way to convert a std::wstring to a std::string. Use std::wstring_convert, WideCharToMultiByte(), or other similar conversion instead. Or, simply do not convert at all, use std::wcout and SetCurrentDirectoryW() instead.

    • you are misusing SO_REUSEADDR. It is useless after bind()/connect(), and you are not even enabling it properly anyway.

    • recv() does not return null-terminated data, like you are expecting. You are likely to experience undesired side effects, if not alright crashes, in your code that tries to match up received strings. TCP is stream oriented, not message oriented, like you think it is. There are numerous posts on StackOverflow that demonstrate the proper way to handle I/O over TCP.

    With all of that said, try something more like this:

    HWND hMyWnd = NULL;
    HANDLE hThread = NULL;
    bool stopThread = false;
    
    int readString(SOCKET sock, char *buf, int buflen, string &str)
    {
        str.clear();
    
        char ch, *pbuf = buf;
        int len = 0, bytesReceived;
    
        do {
            if (stopThread)
                return -2;
    
            bytesReceived = recv(sock, &ch, 1, 0);
    
            if (bytesReceived == -1) {
                if ((WSAGetLastError() != WSAETIMEDOUT) || !str.empty()) {
                    //cerr << "Can't read from socket, Err#" << WSAGetLastError() << endl;
                    return -1;
                }
                return 1;
            }
    
            if (bytesReceived == 0) {
                //cerr << "Socket disconnected by server" << endl;
                return 0;
            }
    
            if (ch == '\0')
                break;
    
            *pbuf++ = ch;
            len += bytesReceived;
    
            if (len == buflen) {
                str.append(buf, len);
                pbuf = buf;
                len = 0;
            }
        }
        while (true);
    
        if (len > 0)
            str.append(buf, len);
    
        return 1;
    }
    
    int sendString(SOCKET sock, const string &str)
    {
        const char *pbuf = str.c_str();
        int len = str.length() + 1, bytesSent;
    
        do {
            if (stopThread)
                return -2;
    
            bytesSent = send(sock, pbuf, len, 0);
    
            if (bytesSent == -1) {
                //cerr << "Can't send to socket, Err#" << WSAGetLastError() << endl;
                return -1;
            }
    
            pbuf += bytesSent;
            len -= bytesSent;
        }
        while (len > 0);
    
        return 1;
    }
    
    //Things to compare
    const char* CreateAccount = "create"; //Server tells client to make IG account
    const char* CheckStatus = "check"; //Client tells server if account is running or not
    const char* Info = "info"; //Client sends Username and Password of account to server
    const char* Run = "run"; //Tells client to start running the account
    const char* Kill = "kill"; //Kills program on client for around a month
    const char* Settings = "settings"; //Server sets settings for account to run on
    
    //Things to send
    const string TryAgain = "#13 Not a valid input, either type [check] to check if the account is running, type [create] to create new account, or type [info] for account information\n";
    const string accInfoSuccess = "#777 You have successfully entered the information for the account (^.^)\n";
    const string settingsInfoSuccess = "#777 You have successfully set the settings for this account (^.^)\n";
    const string accInfoProblem = "#13 There was a problem in either saving the information to this account or the account creation program. Type [create] and try again (T.T)\n";
    const string settingsInfoProblem = "#13 There was a problem in saving the account settings. Type [settings] and try again (T.T)\n";
    const string accRun = "#777 The account is currently running! ~(^.^)~\n";
    const string accNoRun = "#13 Sorry the account isn't running, type [run] to run the account (O.o)\n";
    const string accNoInfo = "#13 There is no info for an account that can be run. Type [create] to make information (\".\")\n";
    const string accRunErr = "#13 There is a problem with opening the main bot program, try again. If this problem persists, there is an issue clientside V(T.T)V\n";
    
    DWORD WINAPI ThreadProc(LPVOID lpParameter)
    {
        string ipAddress = "10.0.0.201"; //IP address of my computer on local network
        int port = 13777;
    
        WSAData data;
        WORD ver = MAKEWORD(2, 2);
        int wsResult = WSAStartup(ver, &data);
        if (wsResult != 0) {
            //cerr << "Can't start Winsock, Err#" << wsResult << endl;
            return 0;
        }
    
        sockaddr_in hint = {};
        hint.sin_family = AF_INET;
        hint.sin_port = htons(port);
        inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
    
        SOCKET sock = INVALID_SOCKET;
        char buf[1024]; //Where message from server will be stored
        string str;
    
        while (!stopThread) {
    
            //attempt to connect to server
    
            sock = socket(AF_INET, SOCK_STREAM, 0);
            if (sock == INVALID_SOCKET) {
                //cerr << "Can't create socket, Err#" << WSAGetLastError() << endl;
                break;
            }
    
            //BOOL on = TRUE;
            //setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
    
            //u_long block = 0;
            //ioctlsocket(sock, FIONBIO, &block);
    
            DWORD timeout = 500;
            setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
            //setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
    
            wsResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
            if (wsResult != SOCKET_ERROR) {
                do {
                    wsResult = readString(sock, buf, sizeof(buf), str);
                    if (wsResult <= 0)
                        break;
    
                    if (!str.empty()) {
                        //Check to see if it equals one of the strings above
                        if (str == CreateAccount) {
                            //Run program to create account
                            if (accountCreation(sock) == 0) {
                                wsResult = sendString(sock, accInfoSuccess);
                            }
                            else {
                                wsResult = sendString(sock, accInfoProblem);
                            }
                        }
                        else if (str == Settings) {
                            if (settingsCreation(sock) == 0) {
                                wsResult = sendString(sock, settingsInfoSuccess);
                            }
                            else {
                                wsResult = sendString(sock, settingsInfoProblem);
                            }
                        }
                        else if (str == CheckStatus) {
                            //Check to see if program that runs account is running
                            int accountSuccess = isRunning();
                            if (accountSuccess == 0) {
                                wsResult = sendString(sock, accRun);
                            }
                            else if (accountSuccess == 1){
                                wsResult = sendString(sock, accNoRun);
                            }
                            else {
                                wsResult = sendString(sock, accNoInfo);
                            }
                        }
                        else if (str == Info) {
                            //Read text file containing account info and send to server
                            if (checkInfo(sock) != 0) {
                                wsResult = sendString(sock, accNoInfo);
                            }
                        }
                        else if (str == Run) {
                            //Runs the account running program
                            if (runProg() == 0) {
                                wsResult = sendString(sock, accRun);
                            }
                            else {
                                wsResult = sendString(sock, accRunErr);
                            }
                        }
                        else if (str == Kill) {
                            //Kills this program
                            PostMessage(hMyWnd, WM_CLOSE, 0, 0);
                            stopThread = true;
                            break;
                        }
                        else {
                            //Send back to server that the wrong thing was inputted
                            wsResult = sendString(sock, TryAgain);
                        }
                    }
                    else {
                        //Check to make sure bot is running
                        if (isRunning() == 1) {
                            //runProg();
                        }
                    }
                }
                while (!stopThread);
            }
    
            closesocket(sock);
            sock = INVALID_SOCKET;
    
            if (!stopThread)
                Sleep(5000);
        }
    
        WSACleanup();
        return 0; 
    }
    
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
        switch (message) {
            case WM_CREATE: {
                hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
                return 0;
            case WM_POWERBROADCAST:
                DestroyWindow(hWnd);
                return 0;
            case WM_DESTROY:
                if (hThread) {
                    stopThread = true;
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                    hThread = NULL;
                }
                PostQuitMessage(0);
                return 0;
            case WM_CLOSE:
                DestroyWindow(hWnd);
                return 0;
        }
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
        //Change the current directory of the program back to the appropriate folder
        wchar_t* UserProf;
        if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &UserProf) == S_OK) {
            wstring wstr = wstring(UserProf) + L"\\UserUpdates";
            //wcout << wstr << endl;
            SetCurrentDirectoryW(wstr.c_str());
            CoTaskMemFree(UserProf);
        }
    
        WNDCLASSW WindowClass{CS_NOCLOSE, WindowProc, 0, 0, hInstance, NULL, LoadCursor(nullptr, IDC_ARROW), NULL, NULL, L"chakra"};
    
        if (!RegisterClassW(&WindowClass)) {
            //cerr << "Can't register window class, Err#" << GetLastError() << endl;
            return 0;
        }
    
        hMyWnd = CreateWindowW(L"chakra", L"star", WS_POPUP, 0, 0, 10, 10, NULL, NULL, hInstance, NULL);
        if (!hMyWnd) {
            //cerr << "Can't create window, Err#" << GetLastError() << endl;
            return 0;
        }
    
        ShowWindow(hMyWnd, SW_HIDE);
    
        MSG Msg;
        while (GetMessage(&Msg, NULL, 0, 0)) {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    
        return 0; 
    }