mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
Windows services can communicate with common processes.
This commit is contained in:
parent
6e635934c1
commit
2d8d6facc3
@ -59,6 +59,10 @@ if (LIBIPC_BUILD_DEMOS)
|
|||||||
add_subdirectory(demo/chat)
|
add_subdirectory(demo/chat)
|
||||||
add_subdirectory(demo/msg_que)
|
add_subdirectory(demo/msg_que)
|
||||||
add_subdirectory(demo/send_recv)
|
add_subdirectory(demo/send_recv)
|
||||||
|
if (MSVC)
|
||||||
|
add_subdirectory(demo/win_service/service)
|
||||||
|
add_subdirectory(demo/win_service/client)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(
|
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 {
|
bool open(char const *name) noexcept {
|
||||||
close();
|
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) {
|
if (h_ == NULL) {
|
||||||
ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name);
|
ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -32,7 +32,7 @@ public:
|
|||||||
close();
|
close();
|
||||||
h_ = ::CreateSemaphore(detail::get_sa(),
|
h_ = ::CreateSemaphore(detail::get_sa(),
|
||||||
static_cast<LONG>(count), LONG_MAX,
|
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) {
|
if (h_ == NULL) {
|
||||||
ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name);
|
ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -33,7 +33,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
HANDLE h;
|
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.
|
// Opens a named file mapping object.
|
||||||
if (mode == open) {
|
if (mode == open) {
|
||||||
h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str());
|
h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user