Skip to content
This repository was archived by the owner on Jan 28, 2022. It is now read-only.

Commit f832dba

Browse files
committed
Add M2Win32Helpers.
1 parent dd0ed7d commit f832dba

4 files changed

Lines changed: 479 additions & 0 deletions

File tree

M2TeamCommonLibrary/M2TeamCommonLibrary.vcxitems

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
<ItemGroup>
1717
<ClCompile Include="$(MSBuildThisFileDirectory)M2BaseHelpers.cpp" />
1818
<ClCompile Include="$(MSBuildThisFileDirectory)M2CXHelpers.cpp" />
19+
<ClCompile Include="$(MSBuildThisFileDirectory)M2Win32Helpers.cpp" />
1920
</ItemGroup>
2021
<ItemGroup>
2122
<ClInclude Include="$(MSBuildThisFileDirectory)M2BaseHelpers.h" />
2223
<ClInclude Include="$(MSBuildThisFileDirectory)M2CXHelpers.h" />
24+
<ClInclude Include="$(MSBuildThisFileDirectory)M2Win32Helpers.h" />
2325
</ItemGroup>
2426
</Project>

M2TeamCommonLibrary/M2TeamCommonLibrary.vcxitems.filters

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
<Filter Include="M2BaseHelpers">
88
<UniqueIdentifier>{3ddd1c92-1b09-47be-a006-c1cadbbdc688}</UniqueIdentifier>
99
</Filter>
10+
<Filter Include="M2Win32Helpers">
11+
<UniqueIdentifier>{75df954e-079c-4788-ab4f-c856a74a7e13}</UniqueIdentifier>
12+
</Filter>
1013
</ItemGroup>
1114
<ItemGroup>
1215
<ClCompile Include="$(MSBuildThisFileDirectory)M2CXHelpers.cpp">
@@ -15,6 +18,9 @@
1518
<ClCompile Include="$(MSBuildThisFileDirectory)M2BaseHelpers.cpp">
1619
<Filter>M2BaseHelpers</Filter>
1720
</ClCompile>
21+
<ClCompile Include="$(MSBuildThisFileDirectory)M2Win32Helpers.cpp">
22+
<Filter>M2Win32Helpers</Filter>
23+
</ClCompile>
1824
</ItemGroup>
1925
<ItemGroup>
2026
<ClInclude Include="$(MSBuildThisFileDirectory)M2CXHelpers.h">
@@ -23,5 +29,8 @@
2329
<ClInclude Include="$(MSBuildThisFileDirectory)M2BaseHelpers.h">
2430
<Filter>M2BaseHelpers</Filter>
2531
</ClInclude>
32+
<ClInclude Include="$(MSBuildThisFileDirectory)M2Win32Helpers.h">
33+
<Filter>M2Win32Helpers</Filter>
34+
</ClInclude>
2635
</ItemGroup>
2736
</Project>
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*
2+
* PROJECT: M2-Team Common Library
3+
* FILE: M2Win32Helpers.cpp
4+
* PURPOSE: Implementation for the Win32 desktop helper functions
5+
*
6+
* LICENSE: The MIT License
7+
*
8+
* DEVELOPER: Mouri_Naruto (Mouri_Naruto AT Outlook.com)
9+
*/
10+
11+
#include "stdafx.h"
12+
13+
#include <Windows.h>
14+
#include <VersionHelpers.h>
15+
16+
#include "M2Win32Helpers.h"
17+
18+
/**
19+
* Obtain the best matching resource with the specified type and name in the
20+
* specified module.
21+
*
22+
* @param lpResourceInfo The resource info which contains the pointer and size.
23+
* @param hModule A handle to the module whose portable executable file or an
24+
* accompanying MUI file contains the resource. If this
25+
* parameter is NULL, the function searches the module used to
26+
* create the current process.
27+
* @param lpType The resource type. Alternately, rather than a pointer, this
28+
* parameter can be MAKEINTRESOURCE(ID), where ID is the integer
29+
* identifier of the given resource type.
30+
* @param lpName The name of the resource. Alternately, rather than a pointer,
31+
* this parameter can be MAKEINTRESOURCE(ID), where ID is the
32+
* integer identifier of the resource.
33+
* @return HRESULT.
34+
*/
35+
HRESULT M2LoadResource(
36+
_Out_ PM2_RESOURCE_INFO lpResourceInfo,
37+
_In_opt_ HMODULE hModule,
38+
_In_ LPCWSTR lpType,
39+
_In_ LPCWSTR lpName)
40+
{
41+
if (nullptr == lpResourceInfo)
42+
return E_INVALIDARG;
43+
44+
SetLastError(ERROR_SUCCESS);
45+
46+
lpResourceInfo->Size = 0;
47+
lpResourceInfo->Pointer = nullptr;
48+
49+
HRSRC ResourceFind = FindResourceExW(
50+
hModule, lpType, lpName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
51+
if (nullptr != ResourceFind)
52+
{
53+
lpResourceInfo->Size = SizeofResource(hModule, ResourceFind);
54+
55+
HGLOBAL ResourceLoad = LoadResource(hModule, ResourceFind);
56+
if (nullptr != ResourceLoad)
57+
{
58+
lpResourceInfo->Pointer = LockResource(ResourceLoad);
59+
}
60+
}
61+
62+
return __HRESULT_FROM_WIN32(GetLastError());
63+
}
64+
65+
/**
66+
* Retrieves the path of the shared Windows directory on a multi-user system.
67+
*
68+
* @param WindowsFolderPath The string of the path of the shared Windows
69+
* directory on a multi-user system.
70+
* @return HRESULT. If the function succeeds, the return value is S_OK.
71+
*/
72+
HRESULT M2GetWindowsDirectory(
73+
std::wstring& WindowsFolderPath)
74+
{
75+
HRESULT hr = S_OK;
76+
77+
do
78+
{
79+
UINT Length = GetSystemWindowsDirectoryW(
80+
nullptr,
81+
0);
82+
if (0 == Length)
83+
{
84+
hr = M2GetLastHRESULTErrorKnownFailedCall();
85+
break;
86+
}
87+
88+
WindowsFolderPath.resize(Length - 1);
89+
90+
Length = GetSystemWindowsDirectoryW(
91+
&WindowsFolderPath[0],
92+
static_cast<UINT>(Length));
93+
if (0 == Length)
94+
{
95+
hr = M2GetLastHRESULTErrorKnownFailedCall();
96+
break;
97+
}
98+
if (WindowsFolderPath.size() != Length)
99+
{
100+
hr = E_UNEXPECTED;
101+
break;
102+
}
103+
104+
} while (false);
105+
106+
if (FAILED(hr))
107+
{
108+
WindowsFolderPath.clear();
109+
}
110+
111+
return hr;
112+
}
113+
114+
/**
115+
* Starts a service if not started and retrieves the current status of the
116+
* specified service.
117+
*
118+
* @param lpServiceName The name of the service to be started. This is the name
119+
* specified by the lpServiceName parameter of the
120+
* CreateService function when the service object was
121+
* created, not the service display name that is shown by
122+
* user interface applications to identify the service.
123+
* The maximum string length is 256 characters. The
124+
* service control manager database preserves the case of
125+
* the characters, but service name comparisons are always
126+
* case insensitive. Forward-slash (/) and backslash ()
127+
* are invalid service name characters.
128+
* @param lpServiceStatus Contains process status information for a service.
129+
* @return HRESULT. If the function succeeds, the return value is S_OK.
130+
*/
131+
HRESULT M2StartService(
132+
_In_ LPCWSTR lpServiceName,
133+
_Out_ LPSERVICE_STATUS_PROCESS lpServiceStatus)
134+
{
135+
M2::CServiceHandle hSCM;
136+
M2::CServiceHandle hService;
137+
138+
DWORD nBytesNeeded = 0;
139+
DWORD nOldCheckPoint = 0;
140+
ULONGLONG nLastTick = 0;
141+
bool bStartServiceWCalled = false;
142+
143+
hSCM = OpenSCManagerW(
144+
nullptr,
145+
nullptr,
146+
SC_MANAGER_CONNECT);
147+
if (!hSCM)
148+
return M2GetLastHRESULTErrorKnownFailedCall();
149+
150+
hService = OpenServiceW(
151+
hSCM,
152+
lpServiceName,
153+
SERVICE_QUERY_STATUS | SERVICE_START);
154+
if (!hService)
155+
return M2GetLastHRESULTErrorKnownFailedCall();
156+
157+
while (QueryServiceStatusEx(
158+
hService,
159+
SC_STATUS_PROCESS_INFO,
160+
reinterpret_cast<LPBYTE>(lpServiceStatus),
161+
sizeof(SERVICE_STATUS_PROCESS),
162+
&nBytesNeeded))
163+
{
164+
if (SERVICE_STOPPED == lpServiceStatus->dwCurrentState)
165+
{
166+
// Failed if the service had stopped again.
167+
if (bStartServiceWCalled)
168+
return E_FAIL;
169+
170+
if (!StartServiceW(hService, 0, nullptr))
171+
return M2GetLastHRESULTErrorKnownFailedCall();
172+
173+
bStartServiceWCalled = true;
174+
}
175+
else if (
176+
SERVICE_STOP_PENDING == lpServiceStatus->dwCurrentState ||
177+
SERVICE_START_PENDING == lpServiceStatus->dwCurrentState)
178+
{
179+
ULONGLONG nCurrentTick = GetTickCount64();
180+
181+
if (!nLastTick)
182+
{
183+
nLastTick = nCurrentTick;
184+
nOldCheckPoint = lpServiceStatus->dwCheckPoint;
185+
186+
// Same as the .Net System.ServiceProcess, wait 250ms.
187+
SleepEx(250, FALSE);
188+
}
189+
else
190+
{
191+
// Check the timeout if the checkpoint is not increased.
192+
if (lpServiceStatus->dwCheckPoint <= nOldCheckPoint)
193+
{
194+
ULONGLONG nDiff = nCurrentTick - nLastTick;
195+
if (nDiff > lpServiceStatus->dwWaitHint)
196+
{
197+
return __HRESULT_FROM_WIN32(ERROR_TIMEOUT);
198+
}
199+
}
200+
201+
// Continue looping.
202+
nLastTick = 0;
203+
}
204+
}
205+
else
206+
{
207+
break;
208+
}
209+
}
210+
211+
return S_OK;
212+
}
213+
214+
/**
215+
* Loads the specified module with the optimization of the mitigation of DLL
216+
* preloading attacks into the address space of the calling process safely. The
217+
* specified module may cause other modules to be loaded.
218+
*
219+
* @param ModuleHandle If the function succeeds, this parameter's value is a
220+
* handle to the loaded module. You should read the
221+
* documentation about LoadLibraryEx API for further
222+
* information.
223+
* @param LibraryFileName A string that specifies the file name of the module
224+
* to load. You should read the documentation about
225+
* LoadLibraryEx API for further information.
226+
* @param Flags The action to be taken when loading the module. You should read
227+
* the documentation about LoadLibraryEx API for further
228+
* information.
229+
* @return HRESULT.
230+
*/
231+
HRESULT M2LoadLibraryEx(
232+
_Out_ HMODULE& ModuleHandle,
233+
_In_ LPCWSTR LibraryFileName,
234+
_In_ DWORD Flags)
235+
{
236+
ModuleHandle = LoadLibraryExW(LibraryFileName, nullptr, Flags);
237+
if (!ModuleHandle)
238+
{
239+
const size_t BufferLength = 32768;
240+
wchar_t Buffer[BufferLength];
241+
242+
if ((Flags & LOAD_LIBRARY_SEARCH_SYSTEM32) &&
243+
(M2GetLastErrorKnownFailedCall() == ERROR_INVALID_PARAMETER))
244+
{
245+
if (!wcschr(LibraryFileName, (wchar_t)'\\'))
246+
{
247+
UINT NewLength = GetSystemDirectoryW(
248+
Buffer,
249+
BufferLength);
250+
251+
Buffer[NewLength++] = '\\';
252+
253+
for (; *LibraryFileName; ++LibraryFileName)
254+
{
255+
Buffer[NewLength++] = *LibraryFileName;
256+
}
257+
258+
Buffer[NewLength] = L'\0';
259+
260+
LibraryFileName = Buffer;
261+
}
262+
263+
ModuleHandle = LoadLibraryExW(LibraryFileName, nullptr, Flags);
264+
}
265+
}
266+
267+
return ModuleHandle ? S_OK : M2GetLastHRESULTErrorKnownFailedCall();
268+
}

0 commit comments

Comments
 (0)