Не получается произвести обмен информацией через shared memory
Я пытаюсь создать сервис и клиент.Они должны обмениваться информацией через shared memory и синхронизироваться через мьютекс.Клиент отправляет сервису название файла и символ для замены пробелов. Сервис вполне неплохо запускается и работает, логи пишут что все успешно: " Служба останавливается. Событие остановки успешно создано. Отображаемая на память область успешно создана. Область памяти успешно отображена. Мьютекс успешно создан. Служба запускается."
Клиент же не может получить доступ к памяти:"Не удалось открыть отображаемую на память область."
Вот код сервиса:
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#define SHARED_MEMORY_NAME TEXT("Global\\MySharedMemory") // Изменено на Global
#define LOG_FILE_PATH "C:\\Users\\vitek\\source\\repos\\Server\\x64\\Debug\\service_log.txt"
#define BUFFER_SIZE 256
SERVICE_STATUS_HANDLE g_ServiceStatusHandle = NULL;
SERVICE_STATUS g_ServiceStatus = { 0 };
HANDLE g_hStopEvent = NULL;
HANDLE g_hLogFile = NULL;
HANDLE g_hMutex = NULL;
char* g_pSharedMemory = NULL;
HANDLE g_hMapFile = NULL; // Глобальная переменная для дескриптора отображаемой области памяти
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
void WINAPI ServiceCtrlHandler(DWORD CtrlCode);
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint);
void ServiceWorkerThread();
void LogEvent(const char* message);
void CreateSharedMemory();
char service[] = TEXT("MyService");
int main() {
SERVICE_TABLE_ENTRY ServiceTable[] = {
{ service, ServiceMain },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) {
printf("StartServiceCtrlDispatcher failed (%d)\n", GetLastError());
}
return 0;
}
void LogEvent(const char* message) {
if (g_hLogFile == NULL) {
g_hLogFile = CreateFile(LOG_FILE_PATH, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (g_hLogFile == INVALID_HANDLE_VALUE) {
return; // Не удалось открыть файл
}
}
DWORD written;
SYSTEMTIME st;
GetSystemTime(&st);
char buffer[256];
sprintf(buffer, "[%04d-%02d-%02d %02d:%02d:%02d] %s\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, message);
WriteFile(g_hLogFile, buffer, strlen(buffer), &written, NULL);
}
void CreateSharedMemory() {
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL; // Используем стандартные права доступа
sa.bInheritHandle = FALSE;
g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0, BUFFER_SIZE, SHARED_MEMORY_NAME);
if (g_hMapFile == NULL) {
LogEvent("Не удалось создать отображаемую на память область.");
return;
}
LogEvent("Отображаемая на память область успешно создана.");
g_pSharedMemory = (char*)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SIZE);
if (g_pSharedMemory == NULL) {
LogEvent("Не удалось отобразить область памяти.");
CloseHandle(g_hMapFile);
g_hMapFile = NULL; // Обнуляем дескриптор
return;
}
LogEvent("Область памяти успешно отображена.");
// Инициализация общей памяти
memset(g_pSharedMemory, 0, BUFFER_SIZE);
}
void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
g_ServiceStatusHandle = RegisterServiceCtrlHandler(TEXT("MyService"), ServiceCtrlHandler);
if (g_ServiceStatusHandle == 0) {
LogEvent("Не удалось зарегистрировать обработчик управления службы.");
return;
}
g_ServiceStatus.dwServiceType = SERVICE_WIN32;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ReportServiceStatus(SERVICE_START_PENDING, NO_ERROR, 0, 3000);
g_hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_hStopEvent == NULL) {
LogEvent("Не удалось создать событие остановки.");
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
return;
}
LogEvent("Событие остановки успешно создано.");
// Создание общей памяти
CreateSharedMemory();
g_hMutex = CreateMutex(NULL, FALSE, TEXT("Global\\MyMutex")); // Изменено на Global
if (g_hMutex == NULL) {
LogEvent("Не удалось создать мьютекс.");
UnmapViewOfFile(g_pSharedMemory);
g_pSharedMemory = NULL; // Обнуляем дескриптор
CloseHandle(g_hMapFile); // Закрываем дескриптор отображаемой области памяти
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
return;
}
LogEvent("Мьютекс успешно создан.");
LogEvent("Служба запускается.");
ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 0, 0);
ServiceWorkerThread();
LogEvent("Служба останавливается.");
ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
// Освобождение ресурсов
if (g_hLogFile != NULL) {
CloseHandle(g_hLogFile);
}
if (g_pSharedMemory != NULL) {
UnmapViewOfFile(g_pSharedMemory);
}
if (g_hMapFile != NULL) {
CloseHandle(g_hMapFile); // Закрываем дескриптор отображаемой области памяти
}
CloseHandle(g_hMutex);
}
void WINAPI ServiceCtrlHandler(DWORD CtrlCode) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP:
LogEvent("Служба останавливается.");
ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0, 0);
SetEvent(g_hStopEvent);
break;
default:
break;
}
}
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) {
g_ServiceStatus.dwCurrentState = dwCurrentState;
g_ServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
g_ServiceStatus.dwCheckPoint = dwCheckPoint;
g_ServiceStatus.dwWaitHint = dwWaitHint;
SetServiceStatus(g_ServiceStatusHandle, &g_ServiceStatus);
}
void ServiceWorkerThread() {
while (WaitForSingleObject(g_hStopEvent, 0) != WAIT_OBJECT_0) {
// Ожидание, пока клиент запишет данные в общую память
WaitForSingleObject(g_hMutex, INFINITE);
// Обработка данных
for (int i = 0; i < BUFFER_SIZE; i++) {
if (g_pSharedMemory[i] == ' ') {
g_pSharedMemory[i] = '_'; // Замена пробелов на символ подчеркивания
}
}
// Логирование обработанных данных
LogEvent(g_pSharedMemory);
ReleaseMutex(g_hMutex);
Sleep(1000); // Имитация работы
}
}
вот код клиента:
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <stdlib.h>
#define SHARED_MEMORY_NAME TEXT("Global\\MySharedMemory") // Изменено на Global
#define LOG_FILE "client_log.txt"
#define BUFFER_SIZE 256
void LogEvent(const char* message);
BOOL IsServiceRunning(const char* serviceName);
int wmain(int argc, wchar_t** argv) {
HANDLE hMutex;
char* g_pSharedMemory;
HANDLE hMapFile;
// Проверка аргументов командной строки
if (argc != 3) {
wprintf(L"Использование: имя_программы имя_входного_файла(на латинице) символ_который_нужно_заменить\n");
LogEvent("Неверное количество аргументов командной строки.");
return -1;
}
// Проверка состояния службы
if (!IsServiceRunning("MyService")) {
wprintf(L"Служба не запущена. Обработка файла невозможна.\n");
LogEvent("Служба не запущена. Обработка файла невозможна.");
return -1;
}
// Открытие отображаемой на память области
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, SHARED_MEMORY_NAME);
if (hMapFile == NULL) {
DWORD error = GetLastError();
wprintf(L"Не удалось открыть отображаемую на память область. Ошибка: %x\n", error);
LogEvent("Не удалось открыть отображаемую на память область.");
return -1;
}
g_pSharedMemory = (char*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SIZE);
if (g_pSharedMemory == NULL) {
DWORD error = GetLastError();
wprintf(L"Не удалось отобразить область памяти. Ошибка: %x\n", error);
LogEvent("Не удалось отобразить область памяти.");
CloseHandle(hMapFile);
return -1;
}
// Создание мьютекса
hMutex = OpenMutex(SYNCHRONIZE, FALSE, TEXT("Global\\MyMutex")); // Изменено на Global
if (hMutex == NULL) {
DWORD error = GetLastError();
wprintf(L"Не удалось открыть мьютекс. Ошибка: %x\n", error);
LogEvent("Не удалось открыть мьютекс.");
UnmapViewOfFile(g_pSharedMemory);
CloseHandle(hMapFile);
return -1;
}
// Преобразование имени входного файла из wchar_t в char
int len = wcslen(argv[1]) + 1; // +1 для нуль-терминатора
char* inputFilename = (char*)malloc(len);
if (inputFilename == NULL) {
wprintf(L"Ошибка выделения памяти.\n");
LogEvent("Ошибка выделения памяти для имени входного файла.");
UnmapViewOfFile(g_pSharedMemory);
CloseHandle(hMapFile);
CloseHandle(hMutex);
return -1;
}
wcstombs(inputFilename, argv[1], len); // Преобразование
// Открытие входного файла
FILE* inputFile = fopen(inputFilename, "r");
if (inputFile == NULL) {
DWORD error = GetLastError();
wprintf(L"Не удалось открыть входной файл. Ошибка: %x\n", error);
LogEvent("Не удалось открыть входной файл.");
LogEvent("Ошибка при открытии входного файла.");
free(inputFilename);
UnmapViewOfFile(g_pSharedMemory);
CloseHandle(hMapFile);
CloseHandle(hMutex);
return -1;
}
// Чтение содержимого файла в общую память
fread(g_pSharedMemory, sizeof(char), BUFFER_SIZE, inputFile);
fclose(inputFile);
// Запись в общую память с использованием мьютекса
WaitForSingleObject(hMutex, INFINITE);
// Замена пробелов на указанный символ
char replaceChar = argv[2][0];
for (int i = 0; i < BUFFER_SIZE; i++) {
if (g_pSharedMemory[i] == ' ') {
g_pSharedMemory[i] = replaceChar; // Замена пробелов на указанный символ
}
}
// Логирование события
char logMessage[256];
sprintf(logMessage, "Обработан файл: %s, заменен пробел на: %c", inputFilename, replaceChar);
LogEvent(logMessage);
ReleaseMutex(hMutex);
// Освобождение ресурсов
free(inputFilename);
UnmapViewOfFile(g_pSharedMemory);
CloseHandle(hMapFile);
CloseHandle(hMutex);
return 0;
}
void LogEvent(const char* message) {
FILE* file = fopen(LOG_FILE, "a");
if (file) {
fprintf(file, "%s\n", message);
fclose(file);
}
else {
// Вывод ошибки, если файл не может быть открыт
printf("Ошибка открытия лог-файла: %s\n", message);
}
}
BOOL IsServiceRunning(const char* serviceName) {
SC_HANDLE schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (schSCManager == NULL) {
LogEvent("Не удалось открыть диспетчер служб.");
return FALSE;
}
SC_HANDLE schService = OpenService(schSCManager, serviceName, SERVICE_QUERY_STATUS);
if (schService == NULL) {
CloseServiceHandle(schSCManager);
LogEvent("Не удалось открыть службу.");
return FALSE;
}
SERVICE_STATUS ss;
BOOL result = QueryServiceStatus(schService, &ss);
if (result) {
result = (ss.dwCurrentState == SERVICE_RUNNING);
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return result;
}
пытался запускать от имени администратора, ставить не global, а local мьютекс и память.