Не работает приложение с использованием: C++ WinApi | Clipboard-WM_RENDERFORMAT | WM_COPYDATA+MapViewOfFile | MessageBox

Приветствую сообщество.

Сейчас я выполняю лабораторку. Суть задачи в создании оконной клиент-серверной системы средствами WinApi. Используется 2 средства передачи данных между процессами:

  • сигнал WM_COPYDATA для сообщений начала передачи; ++ отображение страничного файла в память после сигнала;
  • отложенная запись в буфер.

Через страничный файл перекидывается квадратная матрица шириной в 8, элементами (-9; 9). Через буфер - 4-ре строки текста.

Работает 0\2. В чём проблемы понять не могу. Способы использования данных средств передачи, описанные в мировой сетке - работать отказываются.

В дополнение, MessageBox'ы отказываются выводиться из case-областей, так что пользователь в добавок не получает должной информации.

Прошу спасения. Найдётся кто отважный, что решится пересмотреть весь мой код?

Код клиента:

#define N 8

LONG  WinProcMain(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL RegWinClass(WNDPROC, LPCTSTR, UINT);

HINSTANCE hInst;
HWND hClientWindow;
HANDLE hEvent;

int B[N][N];
HANDLE hMemoryPage;

LPCTSTR ClassNameMain = L"Client_LR6";

const wchar_t* _ch2wch(const char* in_str)
{
    wchar_t* out_str;
    int lenA = strlen(in_str) + 1;
    int lenW = ::MultiByteToWideChar(0, 0, in_str, lenA, NULL, 0);
    if (lenW > 0)
    {
        out_str = new wchar_t[lenW];
        ::MultiByteToWideChar(0, 0, in_str, lenA, out_str, lenW);
        return out_str;
    }
    else return L"err";
}

static bool Put_to_memory()
{
    if (hMemoryPage == 0)
    {
        MessageBox(NULL, L"Передача невозможна", NULL, 0);
        return false;
    }

    int* point2matrix = (int*)MapViewOfFile(hMemoryPage, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    if (point2matrix)
    {
        for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            point2matrix[i * N + j] = B[i][j];
    }
    else
    {
        MessageBox(NULL, L"Не удалось загрузить матрицу", NULL, 0);
        return false;
    }

    UnmapViewOfFile(point2matrix);
    return true;
}

static void Get_from_memory()
{
    char read[1000], buffer[100];

    int* point2matrix = (int*)MapViewOfFile(hMemoryPage, FILE_MAP_ALL_ACCESS, 0, 0, 0);

    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            sprintf_s(buffer, "%d ", *(point2matrix + i * N + j));
            strcat_s(read, buffer);
        }
        strcat_s(read, "\r\n");
    }

    HDC hdc = GetDC(hClientWindow);
    TextOut(hdc, 200, 50, _ch2wch(read), strlen(read));
    ReleaseDC(hClientWindow, hdc);

    UnmapViewOfFile(point2matrix);
    CloseHandle(hMemoryPage);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    HMENU menu;
    hInst = hInstance;

    if (!RegWinClass((WNDPROC)WinProcMain, ClassNameMain, COLOR_WINDOW)) return false;

    menu = LoadMenu(NULL, (LPCWSTR)IDR_MENU1);
    hClientWindow = CreateWindow(ClassNameMain, L"Клиент", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                                 /*x*/500, /*y*/200, /*w*/800, /*h*/400,
                                 NULL, menu, hInstance, NULL);

    if (!hClientWindow)
    {
        MessageBox(NULL, L"Окно не создано", NULL, MB_OK);
        return false;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return int(msg.wParam);
}

BOOL RegWinClass(WNDPROC proc, LPCTSTR lpszClassName, UINT hrBackGround)
{
    WNDCLASS w;
    w.lpszClassName = lpszClassName;
    w.hInstance = hInst;
    w.lpfnWndProc = proc;
    w.hCursor = LoadCursor(NULL, IDC_ARROW);
    w.hIcon = LoadIcon(NULL, lpszClassName);
    w.lpszMenuName = NULL;
    w.hbrBackground = (HBRUSH)(hrBackGround + 1);
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.cbClsExtra = 0;
    w.cbWndExtra = 0;
    return (RegisterClass(&w) != 0);
}

LONG WinProcMain(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static OPENFILENAME ofn;
    static PROCESS_INFORMATION pi;
    STARTUPINFO si;

    static bool is_array_created = false;

    char to_clipboard[] = "строка 1\nстрока 2\nстрока 3\nстрока 4";

    switch (msg)
    {
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case ID_SERVERLOAD: // ВСЕ ID_... - элементы соответствующей окну панели меню
                                    // работают корректно
                {
                    if (FindWindow(L"Server_LR6", NULL) == NULL)
                    {
                        if (GetOpenFileName(&ofn))
                        {
                            ZeroMemory(&pi, sizeof(pi));
                            ZeroMemory(&si, sizeof(si));
                            si.cb = sizeof(si);
                            if (!CreateProcess(ofn.lpstrFile, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
                                MessageBox(NULL, L"Не удалось запустить сервер", NULL, 0);
                        }
                    }
                    else
                        MessageBox(NULL, L"Сервер уже запущен", NULL, 0);
                    break;
                }

                case ID_CREATEMATRIX:
                {
                    int num;
                    std::string s;

                    HDC hdc = GetDC(hClientWindow);
                    for (int i = 0; i < N; i++)
                    {
                        s = "";
                        for (int j = 0; j < N; j++)
                        {
                            num = (rand() % 19) - 9;
                            B[i][j] = num;

                            s += std::to_string(num);
                            s += num < 0 ? " " : "  ";
                        }
                        TextOut(hdc, 50, 15 + i * 20, _ch2wch((s + "\0").c_str()), s.length() + 1);
                    }
                    ReleaseDC(hClientWindow, hdc);

                    is_array_created = true;
                    break;
                }

                case ID_TRANSFERMATRIX:
                {
                    HWND hServerWindow = FindWindow(L"Server_LR6", NULL);
                    if (hServerWindow == NULL)
                    {
                        if (MessageBox(NULL, L"Сервер неактивен", NULL, 0) == IDOK)
                        break;
                    }

                    if (is_array_created == true)
                    {
                        if (!Put_to_memory())
                        {
                            break;
                        }

                        COPYDATASTRUCT cds;
                        cds.dwData = 1; // array
                        cds.cbData = sizeof(hMemoryPage);
                        cds.lpData = hMemoryPage;
                        SendMessage(hServerWindow, WM_COPYDATA, (WPARAM)hServerWindow, (LPARAM)(LPVOID)&cds);

                        MessageBox(NULL, L"Передача завершена", L"Передача массива", 0);
                    }
                    else
                        MessageBox(NULL, L"Сформируйте массив", NULL, 0);

                    break;
                }

                case ID_SHOWOBJECT:
                {
                    MessageBox(NULL, _ch2wch(("Cообщение:\n\n" + std::string(to_clipboard)).c_str()), L"Объект", 0);
                    break;
                }
            }
            break;
        }

        case WM_COPYDATA:
        {
            COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
            if (pcds->dwData == 2) // return
            {
                hMemoryPage = (HANDLE)(pcds->lpData);
            }
            else
                MessageBox(NULL, L"Получено ошибочное сообщение COPYDATA", NULL, 0);

            Get_from_memory();

            break;
        }

        case WM_RENDERALLFORMATS:
        {
            OpenClipboard(hWnd);
            EmptyClipboard();
            SendMessage(hClientWindow, WM_RENDERFORMAT, CF_TEXT, 0L);
            CloseClipboard();
        }

        case WM_RENDERFORMAT:
        {
            if (wParam != CF_TEXT) return 0;

            static HGLOBAL hglbTextCopyBuf;
            LPWSTR lpTextCopy;
            static HGLOBAL hglbTextPasteBuf;
            LPWSTR lpTextPaste;
            static HGLOBAL hglbClipBuf;
            LPWSTR lpClipBuf;

            hglbTextCopyBuf = GlobalAlloc(GHND, sizeof(to_clipboard) + 1);
            if (hglbTextCopyBuf != NULL)
            {
                lpTextCopy = (LPWSTR)GlobalLock(hglbTextCopyBuf);
                if (lpTextCopy != NULL)
                {
                    lstrcpy(lpTextCopy, _ch2wch(to_clipboard));
                    GlobalUnlock(hglbTextCopyBuf);

                    // Фактическая запись данных
                    SetClipboardData(wParam, hglbTextCopyBuf);
                }
                else
                    MessageBox(hWnd, L"Мало памяти", _ch2wch(to_clipboard), MB_OK | MB_ICONHAND);
            }
            else
                MessageBox(hWnd, L"Мало памяти", _ch2wch(to_clipboard), MB_OK | MB_ICONHAND);

            break;
        }

        case WM_CREATE:
        {
            TCHAR szFile[MAX_PATH + 1];
            ZeroMemory(szFile, sizeof(szFile));
            ZeroMemory(&ofn, sizeof(ofn));

            ofn.lStructSize = sizeof(ofn);
            ofn.hwndOwner = hWnd;

            ofn.lpstrFile = szFile;
            ofn.nMaxFile = MAX_PATH;

            ofn.lpstrFilter = TEXT("Execution\0*.EXE\0");
            ofn.nFilterIndex = 1;

            ofn.lpstrFileTitle = NULL;
            ofn.nMaxFileTitle = 0;

            ofn.lpstrInitialDir = NULL;
            ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;

            hMemoryPage = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, L"memory_page");

            OpenClipboard(hClientWindow);
            EmptyClipboard();
            SetClipboardData(CF_TEXT, NULL);
            CloseClipboard();

            // srand(time(NULL));

            break;
        }

        case WM_PAINT:
        {
            break;
        }

        case WM_DESTROY:
        {
            CloseHandle(hMemoryPage);

            PostQuitMessage(0);
            break;
        }

        default:
            return LONG(DefWindowProc(hWnd, msg, wParam, lParam));
    }

    return 0;
}

Код сервера:

#define N 8

LONG  WinProcMain(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL RegWinClass(WNDPROC, LPCTSTR, UINT);

HINSTANCE hInst;
HWND hServerWindow;
LPCTSTR ClassNameMain = L"Server_LR6";

bool is_matrix;
int B[N][N];
HANDLE hMemoryPage;

const wchar_t* _ch2wch(const char* in_str)
{
    wchar_t* out_str;
    int lenA = strlen(in_str) + 1;
    int lenW = ::MultiByteToWideChar(0, 0, in_str, lenA, NULL, 0);
    if (lenW > 0)
    {
        out_str = new wchar_t[lenW];
        ::MultiByteToWideChar(0, 0, in_str, lenA, out_str, lenW);
        return out_str;
    }
    else return L"err";
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    HMENU menu;
    hInst = hInstance;

    if (!RegWinClass((WNDPROC)WinProcMain, ClassNameMain, COLOR_WINDOW)) return false;

    menu = LoadMenu(NULL, (LPCWSTR)IDR_MENU2);

    hServerWindow = CreateWindow(ClassNameMain, L"Сервер", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                            /*x*/500, /*y*/700, /*w*/500, /*h*/200,
                            NULL, menu, hInstance, NULL);

    if (!hServerWindow)
    {
        MessageBox(NULL, L"Окно не создано", NULL, MB_OK);
        return false;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return int(msg.wParam);
}

BOOL RegWinClass(WNDPROC proc, LPCTSTR lpszClassName, UINT hrBackGround)
{
    WNDCLASS w;
    w.lpszClassName = lpszClassName;
    w.hInstance = hInst;
    w.lpfnWndProc = proc;
    w.hCursor = LoadCursor(NULL, IDC_ARROW);
    w.hIcon = LoadIcon(NULL, lpszClassName);
    w.lpszMenuName = NULL;
    w.hbrBackground = (HBRUSH)(hrBackGround + 1);
    w.style = CS_HREDRAW | CS_VREDRAW;
    w.cbClsExtra = 0;
    w.cbWndExtra = 0;
    return (RegisterClass(&w) != 0);
}

static void Get_from_memory()
{
    if (hMemoryPage == 0)
    {
        MessageBox(NULL, L"Получение невозможно", NULL, 0);
        return;
    }

    char str[1000], s[100];

    is_matrix = false;
    int matrix_size = N * N * sizeof(int);

    int* point2matrix = (int*)MapViewOfFile(hMemoryPage, FILE_MAP_ALL_ACCESS, 0, 0, matrix_size); // указатель региона области памяти
    if (point2matrix)
    {
        for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            B[i][j] = point2matrix[i * N + j];

        // освобождаем память, занятую проекцией файла
        UnmapViewOfFile(point2matrix);

        strcpy_s(str, "");
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                sprintf_s(s, "%d\t", B[i][j]);
                strcat_s(str, s);
            }
            strcat_s(str, "\n");
        }
        strcat_s(str, "\x0");

        MessageBox(NULL, (LPWSTR)_ch2wch(str), L"Получена матрица", 0);
        is_matrix = true;
    }
    else
        MessageBox(NULL, L"Память под массив не выделена", NULL, 0);
}

static void Transform_matrix()
{
    if (is_matrix)
    {
        int min[]{ B[0][0], B[1][0], B[2][0], B[3][0], B[4][0], B[5][0], B[6][0], B[7][0] };
        for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
        {
            if (B[i][j] < min[i]) min[i] = B[i][j];
        }

        for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
        {
            B[i][j] = i == j ? min[i] : 0;
        }

        MessageBox(NULL, L"Завершено", L"Преобразование матрицы", 0);
    }
    else
    {
        MessageBox(NULL, L"Матрица не получена", NULL, 0);
    }
}

static bool Put_to_memory()
{
    if (is_matrix)
    {
        int* point2matrix = (int*)MapViewOfFile(hMemoryPage, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        if (point2matrix)
        {
            for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                point2matrix[i * N + j] = B[i][j];
        }
        else
        {
            MessageBox(NULL, L"Не удалось загрузить матрицу", NULL, 0);
            return false;
        }

        UnmapViewOfFile(point2matrix);
    }
    else
    {
        MessageBox(NULL, L"Необходимые операции с матрицей не выполнены", NULL, 0);
        return false;
    }

    return true;
}

LONG WinProcMain(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static HWND hwndNextViewer;
    HGLOBAL hgMem;
    HDC hdcMem;

    switch (msg)
    {
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case ID_GETOBJECT:
                {
                    static HGLOBAL hglbClipBuf;
                    LPWSTR lpClipBuf;

                    OpenClipboard(hWnd);
                    hglbClipBuf = GetClipboardData(CF_TEXT);
                    if (hglbClipBuf != NULL)
                    {
                        lpClipBuf = (LPWSTR)GlobalLock(hglbClipBuf);
                        if (lpClipBuf != NULL)
                        {
                            MessageBox(NULL, lpClipBuf, L"Буфер обмена", MB_OK);
                        }
                        else
                            MessageBox(hWnd, L"Мало памяти", NULL, MB_OK | MB_ICONHAND);
                    }
                    else
                        MessageBox(hWnd, L"Формат CF_TEXT недоступен", NULL, MB_OK | MB_ICONHAND);

                    CloseClipboard();

                    break;
                }
            }
            break;
        }

        case WM_COPYDATA:
        {
            COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
            if (pcds->dwData == 1) // array
            {
                hMemoryPage = (HANDLE)(pcds->lpData);
            }
            else
                MessageBox(NULL, L"Получено ошибочное сообщение COPYDATA", NULL, 0);

            HWND hClientWindow = FindWindow(L"Server_LR6", NULL);
            if (hClientWindow == NULL)
            {
                MessageBox(NULL, L"Пришло сообщение от закрытого клиента", NULL, 0);
                break;
            }

            Get_from_memory();
            Transform_matrix();
            if (!Put_to_memory())
            {
                break;
            }

            COPYDATASTRUCT cds;
            cds.dwData = 2; // return
            cds.cbData = sizeof(hMemoryPage);
            cds.lpData = hMemoryPage;
            SendMessage(hClientWindow, WM_COPYDATA, (WPARAM)hClientWindow, (LPARAM)(LPVOID)&cds);

            break;
        }

        case WM_CREATE:
        {
            hwndNextViewer = SetClipboardViewer(hWnd);
            break;
        }

        case WM_CHANGECBCHAIN:
        {
            if ((HWND)wParam == hwndNextViewer)
                hwndNextViewer = (HWND)lParam;
            else
                if (hwndNextViewer != NULL)
                    SendMessage(hwndNextViewer, msg, wParam, lParam);
            break;
        }

        case WM_DRAWCLIPBOARD:
        {
            if (hwndNextViewer)
                SendMessage(hwndNextViewer, msg, wParam, lParam);
            InvalidateRect(hWnd, NULL, TRUE);
            break;
        }

        case WM_PAINT:
        {
            break;
        }

        case WM_DESTROY:
        {
            ChangeClipboardChain(hWnd, hwndNextViewer);
            PostQuitMessage(0);
            break;
        }

        default:
            return LONG(DefWindowProc(hWnd, msg, wParam, lParam));
    }

    return 0;
}

Ответы (1 шт):

Автор решения: MBo

Работает 0\2 - что означает эта фраза?

Я вижу только один CreateFileMapping, а во второй программе как будет туда доступ? Нужен, видимо, OpenFileMapping, т.к. хэндл hMemoryPage в другой программе не имеет того же значения.

Однако зачем это делать вообще при использовании WM_COPYDATA? Оно само работает через скрытый маппинг , через него можно информацию и передавать, иначе смысла в его использовании большого нет ((правда, всю структуру программы тяжело обозреть)).

Из обработчика WM_COPYDATA сервера вы посылаете такое же сообщение клиенту. Сильно подозреваю, что этого делать нельзя, т.к сообщение синхронное, и может получиться дедлок.

Очень мало проводится проверок и анализа (в т.ч. GetLastError) результатов вызовов функций

→ Ссылка