Не работает приложение с использованием: 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 шт):
Работает 0\2 - что означает эта фраза?
Я вижу только один CreateFileMapping, а во второй программе как будет туда доступ? Нужен, видимо, OpenFileMapping, т.к. хэндл hMemoryPage в другой программе не имеет того же значения.
Однако зачем это делать вообще при использовании WM_COPYDATA? Оно само работает через скрытый маппинг , через него можно информацию и передавать, иначе смысла в его использовании большого нет ((правда, всю структуру программы тяжело обозреть)).
Из обработчика WM_COPYDATA сервера вы посылаете такое же сообщение клиенту. Сильно подозреваю, что этого делать нельзя, т.к сообщение синхронное, и может получиться дедлок.
Очень мало проводится проверок и анализа (в т.ч. GetLastError) результатов вызовов функций