mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Windows services can communicate with common processes.
This commit is contained in:
parent
7981a1cbc1
commit
e229f78a15
@ -59,6 +59,10 @@ if (LIBIPC_BUILD_DEMOS)
|
||||
add_subdirectory(demo/chat)
|
||||
add_subdirectory(demo/msg_que)
|
||||
add_subdirectory(demo/send_recv)
|
||||
if (MSVC)
|
||||
add_subdirectory(demo/win_service/service)
|
||||
add_subdirectory(demo/win_service/client)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(
|
||||
|
||||
8
demo/win_service/client/CMakeLists.txt
Normal file
8
demo/win_service/client/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
project(win_client)
|
||||
|
||||
file(GLOB SRC_FILES ./*.cpp)
|
||||
file(GLOB HEAD_FILES ./*.h)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ipc)
|
||||
28
demo/win_service/client/main.cpp
Normal file
28
demo/win_service/client/main.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/// \brief To create a basic Windows command line program.
|
||||
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libipc/ipc.h"
|
||||
|
||||
int _tmain (int argc, TCHAR *argv[]) {
|
||||
_tprintf(_T("My Sample Client: Entry\n"));
|
||||
ipc::channel ipc_r{"service ipc r", ipc::receiver};
|
||||
ipc::channel ipc_w{"service ipc w", ipc::sender};
|
||||
while (1) {
|
||||
auto msg = ipc_r.recv();
|
||||
if (msg.empty()) {
|
||||
_tprintf(_T("My Sample Client: message recv error\n"));
|
||||
return -1;
|
||||
}
|
||||
printf("My Sample Client: message recv: [%s]\n", (char const *)msg.data());
|
||||
while (!ipc_w.send("Copy.")) {
|
||||
_tprintf(_T("My Sample Client: message send error\n"));
|
||||
Sleep(1000);
|
||||
}
|
||||
_tprintf(_T("My Sample Client: message send [Copy]\n"));
|
||||
}
|
||||
_tprintf(_T("My Sample Client: Exit\n"));
|
||||
return 0;
|
||||
}
|
||||
8
demo/win_service/service/CMakeLists.txt
Normal file
8
demo/win_service/service/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
project(win_service)
|
||||
|
||||
file(GLOB SRC_FILES ./*.cpp)
|
||||
file(GLOB HEAD_FILES ./*.h)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ipc)
|
||||
189
demo/win_service/service/main.cpp
Normal file
189
demo/win_service/service/main.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
/// \brief To create a basic Windows Service in C++.
|
||||
/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
|
||||
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <string>
|
||||
|
||||
#include "libipc/ipc.h"
|
||||
|
||||
SERVICE_STATUS g_ServiceStatus = {0};
|
||||
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
|
||||
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
|
||||
|
||||
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
|
||||
VOID WINAPI ServiceCtrlHandler (DWORD);
|
||||
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);
|
||||
|
||||
#define SERVICE_NAME _T("My Sample Service")
|
||||
|
||||
int _tmain (int argc, TCHAR *argv[]) {
|
||||
OutputDebugString(_T("My Sample Service: Main: Entry"));
|
||||
|
||||
SERVICE_TABLE_ENTRY ServiceTable[] = {
|
||||
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: Main: StartServiceCtrlDispatcher returned error"));
|
||||
return GetLastError ();
|
||||
}
|
||||
|
||||
OutputDebugString(_T("My Sample Service: Main: Exit"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) {
|
||||
DWORD Status = E_FAIL;
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Entry"));
|
||||
|
||||
g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);
|
||||
|
||||
if (g_StatusHandle == NULL) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: RegisterServiceCtrlHandler returned error"));
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// Tell the service controller we are starting
|
||||
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
|
||||
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
g_ServiceStatus.dwControlsAccepted = 0;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
g_ServiceStatus.dwServiceSpecificExitCode = 0;
|
||||
g_ServiceStatus.dwCheckPoint = 0;
|
||||
|
||||
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform tasks neccesary to start the service here
|
||||
*/
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Service Start Operations"));
|
||||
|
||||
// Create stop event to wait on later.
|
||||
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
if (g_ServiceStopEvent == NULL) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error"));
|
||||
|
||||
g_ServiceStatus.dwControlsAccepted = 0;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = GetLastError();
|
||||
g_ServiceStatus.dwCheckPoint = 1;
|
||||
|
||||
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
||||
}
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
// Tell the service controller we are started
|
||||
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
g_ServiceStatus.dwCheckPoint = 0;
|
||||
|
||||
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
||||
}
|
||||
|
||||
// Start the thread that will perform the main task of the service
|
||||
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Waiting for Worker Thread to complete"));
|
||||
|
||||
// Wait until our worker thread exits effectively signaling that the service needs to stop
|
||||
WaitForSingleObject (hThread, INFINITE);
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Worker Thread Stop Event signaled"));
|
||||
|
||||
|
||||
/*
|
||||
* Perform any cleanup tasks
|
||||
*/
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Cleanup Operations"));
|
||||
|
||||
CloseHandle (g_ServiceStopEvent);
|
||||
|
||||
g_ServiceStatus.dwControlsAccepted = 0;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
g_ServiceStatus.dwCheckPoint = 3;
|
||||
|
||||
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
|
||||
}
|
||||
|
||||
EXIT:
|
||||
OutputDebugString(_T("My Sample Service: ServiceMain: Exit"));
|
||||
return;
|
||||
}
|
||||
|
||||
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Entry"));
|
||||
|
||||
switch (CtrlCode) {
|
||||
case SERVICE_CONTROL_STOP :
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request"));
|
||||
|
||||
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Perform tasks neccesary to stop the service here
|
||||
*/
|
||||
|
||||
g_ServiceStatus.dwControlsAccepted = 0;
|
||||
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||||
g_ServiceStatus.dwWin32ExitCode = 0;
|
||||
g_ServiceStatus.dwCheckPoint = 4;
|
||||
|
||||
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
|
||||
}
|
||||
|
||||
// This will signal the worker thread to start shutting down
|
||||
SetEvent (g_ServiceStopEvent);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Exit"));
|
||||
}
|
||||
|
||||
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam) {
|
||||
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));
|
||||
ipc::channel ipc_r{"service ipc r", ipc::sender};
|
||||
ipc::channel ipc_w{"service ipc w", ipc::receiver};
|
||||
|
||||
// Periodically check if the service has been requested to stop
|
||||
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
|
||||
/*
|
||||
* Perform main service function here
|
||||
*/
|
||||
if (!ipc_r.send("Hello, World!")) {
|
||||
OutputDebugString(_T("My Sample Service: send failed."));
|
||||
}
|
||||
else {
|
||||
OutputDebugString(_T("My Sample Service: send [Hello, World!]"));
|
||||
auto msg = ipc_w.recv(1000);
|
||||
if (msg.empty()) {
|
||||
OutputDebugString(_T("My Sample Service: recv error"));
|
||||
} else {
|
||||
OutputDebugStringA((std::string{"My Sample Service: recv ["} + msg.get<char const *>() + "]").c_str());
|
||||
}
|
||||
}
|
||||
Sleep(3000);
|
||||
}
|
||||
|
||||
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
@ -33,7 +33,7 @@ public:
|
||||
|
||||
bool open(char const *name) noexcept {
|
||||
close();
|
||||
h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(name).c_str());
|
||||
h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str());
|
||||
if (h_ == NULL) {
|
||||
ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name);
|
||||
return false;
|
||||
|
||||
@ -32,7 +32,7 @@ public:
|
||||
close();
|
||||
h_ = ::CreateSemaphore(detail::get_sa(),
|
||||
static_cast<LONG>(count), LONG_MAX,
|
||||
ipc::detail::to_tchar(name).c_str());
|
||||
ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str());
|
||||
if (h_ == NULL) {
|
||||
ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name);
|
||||
return false;
|
||||
|
||||
@ -33,7 +33,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
||||
return nullptr;
|
||||
}
|
||||
HANDLE h;
|
||||
auto fmt_name = ipc::detail::to_tchar(ipc::string{"__IPC_SHM__"} + name);
|
||||
auto fmt_name = ipc::detail::to_tchar(ipc::string{"Global\\__IPC_SHM__"} + name);
|
||||
// Opens a named file mapping object.
|
||||
if (mode == open) {
|
||||
h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user