Skip to content

Commit e229f78

Browse files
committed
Windows services can communicate with common processes.
1 parent 7981a1c commit e229f78

File tree

8 files changed

+240
-3
lines changed

8 files changed

+240
-3
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ if (LIBIPC_BUILD_DEMOS)
5959
add_subdirectory(demo/chat)
6060
add_subdirectory(demo/msg_que)
6161
add_subdirectory(demo/send_recv)
62+
if (MSVC)
63+
add_subdirectory(demo/win_service/service)
64+
add_subdirectory(demo/win_service/client)
65+
endif()
6266
endif()
6367

6468
install(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
project(win_client)
2+
3+
file(GLOB SRC_FILES ./*.cpp)
4+
file(GLOB HEAD_FILES ./*.h)
5+
6+
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
7+
8+
target_link_libraries(${PROJECT_NAME} ipc)

demo/win_service/client/main.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// \brief To create a basic Windows command line program.
2+
3+
#include <Windows.h>
4+
#include <tchar.h>
5+
#include <stdio.h>
6+
7+
#include "libipc/ipc.h"
8+
9+
int _tmain (int argc, TCHAR *argv[]) {
10+
_tprintf(_T("My Sample Client: Entry\n"));
11+
ipc::channel ipc_r{"service ipc r", ipc::receiver};
12+
ipc::channel ipc_w{"service ipc w", ipc::sender};
13+
while (1) {
14+
auto msg = ipc_r.recv();
15+
if (msg.empty()) {
16+
_tprintf(_T("My Sample Client: message recv error\n"));
17+
return -1;
18+
}
19+
printf("My Sample Client: message recv: [%s]\n", (char const *)msg.data());
20+
while (!ipc_w.send("Copy.")) {
21+
_tprintf(_T("My Sample Client: message send error\n"));
22+
Sleep(1000);
23+
}
24+
_tprintf(_T("My Sample Client: message send [Copy]\n"));
25+
}
26+
_tprintf(_T("My Sample Client: Exit\n"));
27+
return 0;
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
project(win_service)
2+
3+
file(GLOB SRC_FILES ./*.cpp)
4+
file(GLOB HEAD_FILES ./*.h)
5+
6+
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
7+
8+
target_link_libraries(${PROJECT_NAME} ipc)

demo/win_service/service/main.cpp

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/// \brief To create a basic Windows Service in C++.
2+
/// \see https://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
3+
4+
#include <Windows.h>
5+
#include <tchar.h>
6+
#include <string>
7+
8+
#include "libipc/ipc.h"
9+
10+
SERVICE_STATUS g_ServiceStatus = {0};
11+
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
12+
HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE;
13+
14+
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv);
15+
VOID WINAPI ServiceCtrlHandler (DWORD);
16+
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam);
17+
18+
#define SERVICE_NAME _T("My Sample Service")
19+
20+
int _tmain (int argc, TCHAR *argv[]) {
21+
OutputDebugString(_T("My Sample Service: Main: Entry"));
22+
23+
SERVICE_TABLE_ENTRY ServiceTable[] = {
24+
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
25+
{NULL, NULL}
26+
};
27+
28+
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE) {
29+
OutputDebugString(_T("My Sample Service: Main: StartServiceCtrlDispatcher returned error"));
30+
return GetLastError ();
31+
}
32+
33+
OutputDebugString(_T("My Sample Service: Main: Exit"));
34+
return 0;
35+
}
36+
37+
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) {
38+
DWORD Status = E_FAIL;
39+
40+
OutputDebugString(_T("My Sample Service: ServiceMain: Entry"));
41+
42+
g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler);
43+
44+
if (g_StatusHandle == NULL) {
45+
OutputDebugString(_T("My Sample Service: ServiceMain: RegisterServiceCtrlHandler returned error"));
46+
goto EXIT;
47+
}
48+
49+
// Tell the service controller we are starting
50+
ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus));
51+
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
52+
g_ServiceStatus.dwControlsAccepted = 0;
53+
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
54+
g_ServiceStatus.dwWin32ExitCode = 0;
55+
g_ServiceStatus.dwServiceSpecificExitCode = 0;
56+
g_ServiceStatus.dwCheckPoint = 0;
57+
58+
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
59+
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
60+
}
61+
62+
/*
63+
* Perform tasks neccesary to start the service here
64+
*/
65+
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Service Start Operations"));
66+
67+
// Create stop event to wait on later.
68+
g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
69+
if (g_ServiceStopEvent == NULL) {
70+
OutputDebugString(_T("My Sample Service: ServiceMain: CreateEvent(g_ServiceStopEvent) returned error"));
71+
72+
g_ServiceStatus.dwControlsAccepted = 0;
73+
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
74+
g_ServiceStatus.dwWin32ExitCode = GetLastError();
75+
g_ServiceStatus.dwCheckPoint = 1;
76+
77+
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
78+
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
79+
}
80+
goto EXIT;
81+
}
82+
83+
// Tell the service controller we are started
84+
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
85+
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
86+
g_ServiceStatus.dwWin32ExitCode = 0;
87+
g_ServiceStatus.dwCheckPoint = 0;
88+
89+
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
90+
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
91+
}
92+
93+
// Start the thread that will perform the main task of the service
94+
HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
95+
96+
OutputDebugString(_T("My Sample Service: ServiceMain: Waiting for Worker Thread to complete"));
97+
98+
// Wait until our worker thread exits effectively signaling that the service needs to stop
99+
WaitForSingleObject (hThread, INFINITE);
100+
101+
OutputDebugString(_T("My Sample Service: ServiceMain: Worker Thread Stop Event signaled"));
102+
103+
104+
/*
105+
* Perform any cleanup tasks
106+
*/
107+
OutputDebugString(_T("My Sample Service: ServiceMain: Performing Cleanup Operations"));
108+
109+
CloseHandle (g_ServiceStopEvent);
110+
111+
g_ServiceStatus.dwControlsAccepted = 0;
112+
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
113+
g_ServiceStatus.dwWin32ExitCode = 0;
114+
g_ServiceStatus.dwCheckPoint = 3;
115+
116+
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
117+
OutputDebugString(_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
118+
}
119+
120+
EXIT:
121+
OutputDebugString(_T("My Sample Service: ServiceMain: Exit"));
122+
return;
123+
}
124+
125+
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) {
126+
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Entry"));
127+
128+
switch (CtrlCode) {
129+
case SERVICE_CONTROL_STOP :
130+
131+
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SERVICE_CONTROL_STOP Request"));
132+
133+
if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
134+
break;
135+
136+
/*
137+
* Perform tasks neccesary to stop the service here
138+
*/
139+
140+
g_ServiceStatus.dwControlsAccepted = 0;
141+
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
142+
g_ServiceStatus.dwWin32ExitCode = 0;
143+
g_ServiceStatus.dwCheckPoint = 4;
144+
145+
if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) {
146+
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
147+
}
148+
149+
// This will signal the worker thread to start shutting down
150+
SetEvent (g_ServiceStopEvent);
151+
152+
break;
153+
154+
default:
155+
break;
156+
}
157+
158+
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: Exit"));
159+
}
160+
161+
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam) {
162+
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Entry"));
163+
ipc::channel ipc_r{"service ipc r", ipc::sender};
164+
ipc::channel ipc_w{"service ipc w", ipc::receiver};
165+
166+
// Periodically check if the service has been requested to stop
167+
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0) {
168+
/*
169+
* Perform main service function here
170+
*/
171+
if (!ipc_r.send("Hello, World!")) {
172+
OutputDebugString(_T("My Sample Service: send failed."));
173+
}
174+
else {
175+
OutputDebugString(_T("My Sample Service: send [Hello, World!]"));
176+
auto msg = ipc_w.recv(1000);
177+
if (msg.empty()) {
178+
OutputDebugString(_T("My Sample Service: recv error"));
179+
} else {
180+
OutputDebugStringA((std::string{"My Sample Service: recv ["} + msg.get<char const *>() + "]").c_str());
181+
}
182+
}
183+
Sleep(3000);
184+
}
185+
186+
OutputDebugString(_T("My Sample Service: ServiceWorkerThread: Exit"));
187+
188+
return ERROR_SUCCESS;
189+
}

src/libipc/platform/win/mutex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class mutex {
3333

3434
bool open(char const *name) noexcept {
3535
close();
36-
h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(name).c_str());
36+
h_ = ::CreateMutex(detail::get_sa(), FALSE, ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str());
3737
if (h_ == NULL) {
3838
ipc::error("fail CreateMutex[%lu]: %s\n", ::GetLastError(), name);
3939
return false;

src/libipc/platform/win/semaphore.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class semaphore {
3232
close();
3333
h_ = ::CreateSemaphore(detail::get_sa(),
3434
static_cast<LONG>(count), LONG_MAX,
35-
ipc::detail::to_tchar(name).c_str());
35+
ipc::detail::to_tchar(ipc::string{"Global\\"} + name).c_str());
3636
if (h_ == NULL) {
3737
ipc::error("fail CreateSemaphore[%lu]: %s\n", ::GetLastError(), name);
3838
return false;

src/libipc/platform/win/shm_win.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ id_t acquire(char const * name, std::size_t size, unsigned mode) {
3333
return nullptr;
3434
}
3535
HANDLE h;
36-
auto fmt_name = ipc::detail::to_tchar(ipc::string{"__IPC_SHM__"} + name);
36+
auto fmt_name = ipc::detail::to_tchar(ipc::string{"Global\\__IPC_SHM__"} + name);
3737
// Opens a named file mapping object.
3838
if (mode == open) {
3939
h = ::OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, fmt_name.c_str());

0 commit comments

Comments
 (0)