Search code examples
c++winapiwinmainmailslot

WinMain Parameter -> Mailslot -> File -> Encoding?


I've got the following problem: An application calls every second a C++ program with some parameters to extract data from this application. The C++ programm is a WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) to accomplish that the console-window is not shown to the user. This "first program" checks data and then writes it into an Mailslot, hosted by my "second program" (just a normal int main() C++). This already works like written above, BUT when I try to read the contents of the mailslot the encoding seems to be different because my parameters are not readable and the length of the string is different.

both programs are using Unicode in their properties. I tried both using LPWSTR (for Unicode) and LPCSTR (for ANSI) and the corresponding functions ...W and ...A but I didn't get it working. below i've written my "LPCSTR-Version" of my 2 programs.

My first program looks like this:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
{
    // here I do: string test = szCmdLine;
    // the parameters are like: "k1234.1234 4321.321 0 1"
    // so there is no special character, just two double and to int
    // asking for minimum length and number of spaces in it to get number of parameters
    // if there is anything not ok I return "",
    // if there is all ok, I return szCmdLine.
    LPCSTR message = processParameter((LPCSTR)szCmdLine);

    if (strcmp('', message) == 0)
        return 0;

    HANDLE hSlot;

    hSlot = CreateFile(
        L"\\\\.\\mailslot\\name\\of\\the\\slot",
        GENERIC_WRITE,              // DesiredAccess
        FILE_SHARE_READ,            // ShareMode
        (LPSECURITY_ATTRIBUTES)NULL,// SecurityAttributes
        OPEN_EXISTING,              // CreationDisposition
        FILE_ATTRIBUTE_NORMAL,      // FlagsAndAttributes
        (HANDLE)NULL                // TemplateFile
        );

    if (hSlot == INVALID_HANDLE_VALUE)
        return 0;

    // send message
    BOOL fResult;
    DWORD cbWritten;

    fResult = WriteFile(
        hSlot,
        message,
        (DWORD)(lstrlenA(message) + 1)*sizeof(char),
        &cbWritten,
        (LPOVERLAPPED)NULL
        );  

    // Handle Clean-up
    CloseHandle(hFile);

    return 0;
}

In my second program looks like this:

HANDLE hMailSlot    = NULL;

BOOL WINAPI createMailSlot()
{
    hMailSlot = CreateMailslot(
        L"\\\\.\\mailslot\\name\\of\\the\\slot",
        0,                          // no maximum message size 
        MAILSLOT_WAIT_FOREVER,      // no time-out for operations 
        (LPSECURITY_ATTRIBUTES)NULL // default security
        );

    if (hMailSlot == INVALID_HANDLE_VALUE)
    {
        printf("CreateMailslot failed with error %d\n", GetLastError());
        return FALSE;
    }
    else
    {
        printf("Mailslot created successfully.\n");
    }

    return TRUE;
}

void processMessage(LPCSTR msg)
{
    string message = msg;

    // DEBUGGING
    cout << "Message: " << message << endl;
    cout << "length:  " << message.length() << endl;

    // do other things...
}

BOOL readSlot()
{
    DWORD cbMessage;
    DWORD cMessage;
    DWORD cbRead;
    BOOL fResult;
    LPCSTR lpszBuffer;
    CHAR achID[80];
    DWORD cAllMessages;
    HANDLE hEvent;
    OVERLAPPED ov;

    cbMessage = cMessage = cbRead = 0;

    hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
    if (NULL == hEvent)
    {
        return FALSE;
    }
    ov.Offset = 0;
    ov.OffsetHigh = 0;
    ov.hEvent = hEvent;

    fResult = GetMailslotInfo(
        hMailSlot,      // mailslot handle 
        (LPDWORD)NULL,  // no maximum message size 
        &cbMessage,     // size of next message 
        &cMessage,      // number of messages 
        (LPDWORD)NULL   // no read time-out
        );
    if (!fResult)
    {
        printf("GetMailslotInfo failed with %d.\n", GetLastError());
        CloseHandle(hEvent);
        return FALSE;
    }

    if (cbMessage == MAILSLOT_NO_MESSAGE)
    {
        printf("Waiting for a message...\n");
        CloseHandle(hEvent);
        return TRUE;
    }

    cAllMessages = cMessage;

    while (cMessage != 0)  // retrieve all messages
    {
        // Create a message-number string. 
        StringCchPrintfA(
            achID,
            80,
            "",
            cAllMessages - cMessage + 1,
            cAllMessages);

        // Allocate memory for the message.
        lpszBuffer = (LPCSTR)GlobalAlloc(
            GPTR,
            cbMessage
            );
        if (NULL == lpszBuffer)
        {
            CloseHandle(hEvent);
            return FALSE;
        }

        fResult = ReadFile(
            hMailSlot,
            (LPVOID)lpszBuffer,
            cbMessage,
            &cbRead,
            &ov
            );

        if (!fResult)
        {
            printf("ReadFile failed with %d.\n", GetLastError());
            GlobalFree((HGLOBAL)lpszBuffer);
            CloseHandle(hEvent);
            return FALSE;
        }

        // process Message
        processMessage(lpszBuffer);

        // Concatenate the message and the message-number string. 

        StringCbCatA(
            (STRSAFE_LPSTR)lpszBuffer,
            cbMessage,
            achID
            );

        GlobalFree((HGLOBAL)lpszBuffer);

        fResult = GetMailslotInfo(
            hMailSlot,      // mailslot handle 
            (LPDWORD)NULL,  // no maximum message size 
            &cbMessage,     // size of next message 
            &cMessage,      // number of messages 
            (LPDWORD)NULL   // no read time-out
            );

        if (!fResult)
        {
            printf("GetMailslotInfo failed (%d)\n", GetLastError());
            CloseHandle(hEvent);
            return FALSE;
        }
    }
    CloseHandle(hEvent);
    return TRUE;
}

int main()
{
    if(!createMailSlot())
        return 1;

    while (true)
    {
        // check Mailslot for messages
        readSlot();

        Sleep(1000);
    }
    return 0;
}

processMessage() gives then a different parameter-string than submitted to my first program. It looks quite weird and is not readable...

Is there a solution for my problem? Where are my faults?

EDIT: I edited my whole question including the source code, to show my latest version.


Solution

  • finally I found a solution for my problem. I just copied again the example-code of MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365576%28v=vs.85%29.aspx) and then googled around. I found this site http://www.johndcook.com/blog/cplusplus_strings/ where all string representations are listed and explained. I changed some passages of my code and this is my working version:

    first program:

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
    {
        // get parameters
        char *parameter = szCmdLine;
    
        // validate parameters
        if (!test_parameter(parameter))
        {
            return 1;
        }
    
        // Convert char* to a wchar_t*
        size_t origsize = strlen(parameter) + 1;
        const size_t newsize = 100;
        size_t convertedChars = 0;
        wchar_t wcstring[newsize];
        mbstowcs_s(&convertedChars, wcstring, origsize, parameter, _TRUNCATE);
        // Source: https://msdn.microsoft.com/en-us/library/ms235631(VS.80).aspx
    
        HANDLE hMailSlot;
    
        hMailSlot = CreateFile(
            L"\\\\.\\mailslot\\name\\of\\the\\MailSlot",    // lpFileName
            GENERIC_WRITE,              // DesiredAccess
            FILE_SHARE_READ,            // ShareMode
            (LPSECURITY_ATTRIBUTES)NULL,// SecurityAttributes
            OPEN_EXISTING,              // CreationDisposition
            FILE_ATTRIBUTE_NORMAL,      // FlagsAndAttributes
            (HANDLE)NULL                // TemplateFile
            );
    
        // testing mailslot
        if (hMailSlot == INVALID_HANDLE_VALUE)
        {
            return 2;
        }
    
        BOOL fResult;
        DWORD cbWritten;
    
        // convert message to TCHAR for sending
        TCHAR *message = wcstring;
    
        // send message
        fResult = WriteFile(
            hMailSlot,                                      // File
            message,                                        // Buffer
            (DWORD)(lstrlen(message) + 1)*sizeof(TCHAR),    // NumberOfBytesToWrite
            &cbWritten,                                     // NumberOfBytesWritten
            (LPOVERLAPPED)NULL                              // Overlapped
            );                          
    
        // Handle Clean-up
        CloseHandle(hMailSlot);
    
        return 0;
    }
    

    second program:

    HANDLE hMailSlot = NULL;
    
    BOOL WINAPI createMailSlot()
    {
        hMailSlot = CreateMailslot(
            L"\\\\.\\mailslot\\name\\of\\the\\MailSlot",            // Slot Name
            0,                          // no maximum message size 
            MAILSLOT_WAIT_FOREVER,      // no time-out for operations 
            (LPSECURITY_ATTRIBUTES)NULL // default security
            );
    
        if (hMailSlot == INVALID_HANDLE_VALUE)
        {
            printf("CreateMailslot failed with error %d\n", GetLastError());
            return FALSE;
        }
        else
        {
            printf("Mailslot created successfully.\n");
        }
    
        return TRUE;
    }
    
    void processMessage(LPTSTR msg)
    {
        // convert LPTSTR to string
        wchar_t *message_w = msg;
        size_t max = 100;
        char *message_c = new char[wcslen(message_w)];
        size_t message_c_size = 100;
        size_t *NumOfCharConverted = 0;
        wcstombs_s(NumOfCharConverted, message_c, message_c_size, message_w, max);
        string message(message_c);
    
        // processs message as string...
    }
    
    BOOL readSlot()
    {
        DWORD cbMessage, cMessage, cbRead;
        BOOL fResult;
        LPTSTR lpszBuffer;
        TCHAR achID[80];
        DWORD cAllMessages;
        HANDLE hEvent;
        OVERLAPPED ov;
    
        cbMessage = cMessage = cbRead = 0;
    
        hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("ExampleSlot"));
        if (NULL == hEvent)
            return FALSE;
        ov.Offset = 0;
        ov.OffsetHigh = 0;
        ov.hEvent = hEvent;
    
        fResult = GetMailslotInfo(
            hMailSlot,      // mailslot handle 
            (LPDWORD)NULL,  // no maximum message size 
            &cbMessage,     // size of next message 
            &cMessage,      // number of messages 
            (LPDWORD)NULL); // no read time-out 
    
        if (!fResult)
        {
            printf("GetMailslotInfo failed with %d.\n", GetLastError());
            return FALSE;
        }
    
        if (cbMessage == MAILSLOT_NO_MESSAGE)
        {
            printf("Waiting for a message...\n");
            return TRUE;
        }
    
        cAllMessages = cMessage;
    
        while (cMessage != 0)  // retrieve all messages
        {
            // Create a message-number string. 
    
            StringCchPrintf((LPTSTR)achID,
                80,
                TEXT(""), //TEXT("\nMessage #%d of %d\n"),
                cAllMessages - cMessage + 1,
                cAllMessages);
    
            // Allocate memory for the message. 
    
            lpszBuffer = (LPTSTR)GlobalAlloc(GPTR,
                lstrlen((LPTSTR)achID)*sizeof(TCHAR) + cbMessage);
            if (NULL == lpszBuffer)
                return FALSE;
            lpszBuffer[0] = '\0';
    
            fResult = ReadFile(
                hMailSlot,
                lpszBuffer,
                cbMessage,
                &cbRead,
                &ov);
    
            if (!fResult)
            {
                printf("ReadFile failed with %d.\n", GetLastError());
                GlobalFree((HGLOBAL)lpszBuffer);
                return FALSE;
            }
    
    
            processMessage(lpszBuffer);
    
            // Concatenate the message and the message-number string. 
    
            StringCbCat(lpszBuffer,
                lstrlen((LPTSTR)achID)*sizeof(TCHAR) + cbMessage,
                (LPTSTR)achID);
    
            // Display the message. 
    
            _tprintf(TEXT("Contents of the mailslot: %s\n"), lpszBuffer);
    
            GlobalFree((HGLOBAL)lpszBuffer);
    
            fResult = GetMailslotInfo(
                hMailSlot,      // mailslot handle 
                (LPDWORD)NULL,  // no maximum message size 
                &cbMessage,     // size of next message 
                &cMessage,      // number of messages 
                (LPDWORD)NULL); // no read time-out 
    
            if (!fResult)
            {
                printf("GetMailslotInfo failed (%d)\n", GetLastError());
                return FALSE;
            }
        }
        CloseHandle(hEvent);
        return TRUE;
    }
    
    int main()
    {
        if(!createMailSlot())
            return 1;
    
        while (true)
        {
            // check Mailslot for messages
            readSlot();
    
            Sleep(1000);
        }
        return 0;
    }