Use Slim Reader/Writer lock to replace CRITICAL_SECTION (better performance).
[gdipp.git] / gdipp_client / api_override.cpp
blobb1b8010544e71fb165a37c9db7482fe95d1e2e3a
1 #include "stdafx.h"
2 #include "api_override.h"
3 #include "gdipp_client/gdi_painter.h"
4 #include "gdipp_client/global.h"
5 #include "gdipp_client/helper.h"
6 #include "gdipp_lib/scoped_rw_lock.h"
7 #include "gdipp_rpc/gdipp_rpc.h"
9 namespace gdipp
12 std::set<HDC> hdc_in_path;
14 bool is_valid_dc(HDC hdc)
16 if (hdc == NULL)
17 return false;
19 // probably a printer
20 if (GetDeviceCaps(hdc, TECHNOLOGY) != DT_RASDISPLAY)
21 return false;
23 // the DC use another std::map mode, which transform the GDI coordination space
24 // we tried to implement MM_ANISOTROPIC, and found that the text looks worse than the native API
25 if (GetMapMode(hdc) != MM_TEXT)
26 return false;
29 if ExtTextOut is called within an open path bracket, different draw function is required
30 because GDI renders the path outline pretty good, and path is rarely used (one example is Google Earth)
31 gdipp does not render HDC with path
33 if (hdc_in_path.find(hdc) != hdc_in_path.end())
34 return false;
36 return true;
39 bool is_target_text(HDC hdc, bool is_glyph_index, LPCWSTR lpString, size_t c, const wchar_t *target_text, int start_index)
42 return true if the current string is the target text (string or glyph index array)
43 otherwise return false
44 always return true if the target is invalid
47 bool is_target;
49 if (target_text == NULL)
50 return true;
52 if (c == 0)
53 c = wcslen(lpString);
54 c -= start_index;
56 const size_t cmp_len = min(c, wcslen(target_text));
57 if (cmp_len == 0)
58 return true;
60 if (is_glyph_index)
62 WORD *gi = new WORD[cmp_len];
63 GetGlyphIndicesW(hdc, target_text, static_cast<int>(cmp_len), gi, 0);
65 is_target = (wmemcmp(lpString + start_index, reinterpret_cast<const wchar_t *>(gi), cmp_len) == 0);
67 delete[] gi;
69 else
70 is_target = (wcsncmp(lpString + start_index, target_text, cmp_len) == 0);
72 return is_target;
75 bool fetch_glyph_run (bool is_glyph_index,
76 bool is_pdy,
77 LPCWSTR lpString,
78 UINT c,
79 CONST INT *lpDx,
80 const dc_context &context,
81 FT_Render_Mode render_mode,
82 glyph_run &a_glyph_run,
83 GLYPH_CACHE_LEVEL &cache_level)
85 bool b_ret;
86 renderer *renderer;
88 switch (context.setting_cache->renderer)
90 case RENDERER_CLEARTYPE:
91 return false;
92 case RENDERER_GETGLYPHOUTLINE:
93 renderer = new ggo_renderer;
94 cache_level = SINGLE_GLYPH;
95 break;
96 case RENDERER_DIRECTWRITE:
97 renderer = new dw_renderer;
98 cache_level = GLYPH_RUN;
99 break;
100 case RENDERER_WIC:
101 renderer = new wic_renderer;
102 cache_level = NONE;
103 break;
104 default:
105 renderer = new ft_renderer;
106 cache_level = SINGLE_GLYPH;
107 break;
110 b_ret = renderer->begin(&context, render_mode);
111 if (b_ret)
113 if (cache_level >= GLYPH_RUN)
114 b_ret = renderer->fetch_glyph_run(is_glyph_index, is_pdy, lpString, c, lpDx, a_glyph_run);
116 renderer->end();
119 delete renderer;
121 return b_ret;
125 void adjust_glyph_bbox(bool is_pdy, CONST INT *lpDx, int char_extra, gdipp_rpc_bitmap_glyph_run *glyph_run, INT *ctrl_right, INT *black_right)
128 adjust the glyph boxes from distance array
130 the dx array stores the distance from the left border of the current glyph to the next glyph
131 the count of such array should be no less than the count of glyphs
132 the last element indicates the distance between the right border of the control box of the glyph run and the left border of the last glyph
133 if pdy flag is set, every 2 elements specifies the distance of the glyph in both X and Y axis
135 gdipp matches the metrics of the glyph control box against the dx array, then adjusts black box accordingly
136 dx array is application specific, therefore the boxes after adjustment are not cached
139 assert(lpDx != NULL || char_extra != 0);
141 const BYTE dx_skip = (is_pdy ? 2 : 1);
142 *ctrl_right = 0;
143 *black_right = 0;
145 for (UINT i = 0; i < glyph_run->count; ++i)
147 if (i != 0)
149 // distance to shift right
150 const int distance_shift = *ctrl_right - glyph_run->ctrl_boxes[i].left + char_extra;
152 glyph_run->ctrl_boxes[i].left += distance_shift;
153 glyph_run->ctrl_boxes[i].right += distance_shift;
154 glyph_run->black_boxes[i].left += distance_shift;
155 glyph_run->black_boxes[i].right += distance_shift;
158 if (lpDx == NULL)
159 *ctrl_right = glyph_run->ctrl_boxes[i].right;
160 else
161 *ctrl_right += lpDx[i * dx_skip];
162 *black_right = glyph_run->black_boxes[i].right;
165 *black_right = max(*black_right, *ctrl_right);
168 BOOL WINAPI ExtTextOutW_hook(HDC hdc, int x, int y, UINT options, CONST RECT * lprect, LPCWSTR lpString, UINT c, CONST INT *lpDx)
170 bool b_ret;
171 dc_context context;
172 gdipp_rpc_bitmap_glyph_run glyph_run = {};
174 // all GDI text painting functions calls ExtTextOutW eventually
176 // no text to output
177 if (lpString == NULL || c == 0)
178 goto fail_safe_text_out;
180 // rectangle is required but not specified
181 // invalid call
182 if (((options & ETO_OPAQUE) || (options & ETO_CLIPPED)) && (lprect == NULL))
183 goto fail_safe_text_out;
185 // completely clipped
186 if ((options & ETO_CLIPPED) && IsRectEmpty(lprect))
187 goto fail_safe_text_out;
189 if (!is_valid_dc(hdc))
190 goto fail_safe_text_out;
192 const bool is_glyph_index = !!(options & ETO_GLYPH_INDEX);
193 const bool is_pdy = !!(options & ETO_PDY);
195 #ifdef _DEBUG
196 bool is_target_spec = false;
197 //is_target_spec |= (x > 0);
198 //is_target_spec |= (y > 0);
199 //is_target_spec |= !!(options & ETO_GLYPH_INDEX));
200 //is_target_spec |= !(options & ETO_GLYPH_INDEX);
201 //is_target_spec |= (options == 4102);
202 //is_target_spec |= (c == 17);
203 if (is_target_spec)
204 int a = 0;
205 else
206 ;//goto fail_safe_text_out;
208 const wchar_t *debug_text;
209 debug_text = NULL;
210 if (!is_target_text(hdc, is_glyph_index, lpString, c, debug_text, 0))
211 goto fail_safe_text_out;
212 //int a = 0;
213 #endif // _DEBUG
215 // uncomment this lock to make rendering single-threaded
216 //gdipp::lock("debug");
218 // initialize the context of the current DC
219 if (!context.init(hdc))
220 goto fail_safe_text_out;
222 // create painter and paint the glyph run
223 error_status_t e;
224 GDIPP_RPC_SESSION_HANDLE h_session = NULL;
225 e = gdipp_rpc_begin_session(h_gdipp_rpc, reinterpret_cast<const byte *>(&context.log_font), sizeof(context.log_font), context.bmp_header.biBitCount, &h_session);
226 if (e != 0 || h_session == NULL)
227 goto fail_safe_text_out;
229 e = gdipp_rpc_make_bitmap_glyph_run(h_gdipp_rpc, h_session, lpString, c, is_glyph_index, &glyph_run);
230 gdipp_rpc_end_session(h_gdipp_rpc, &h_session);
231 if (e != 0)
232 goto fail_safe_text_out;
234 const int char_extra = GetTextCharacterExtra(hdc);
235 if (char_extra == 0x8000000)
236 goto fail_safe_text_out;
238 INT ctrl_right, black_right;
239 if (lpDx == NULL && char_extra == 0)
241 ctrl_right = glyph_run.ctrl_boxes[glyph_run.count - 1].right;
242 black_right = glyph_run.black_boxes[glyph_run.count - 1].right;
244 else
246 adjust_glyph_bbox(!!(options & ETO_PDY), lpDx, char_extra, &glyph_run, &ctrl_right, &black_right);
249 painter *painter;
250 switch (client_config_instance.painter)
252 case client_config::PAINTER_D2D:
253 //painter = new gdimm_wic_painter;
254 //break;
255 default:
256 painter = new gdi_painter;
257 break;
260 b_ret = painter->begin(&context);
261 if (b_ret)
263 b_ret = painter->paint(x, y, options, lprect, glyph_run, ctrl_right, black_right);
264 painter->end();
266 delete painter;
268 for (UINT i = 0; i < glyph_run.count; ++i)
270 if (glyph_run.glyphs[i].buffer != NULL)
271 MIDL_user_free(glyph_run.glyphs[i].buffer);
273 MIDL_user_free(glyph_run.glyphs);
274 MIDL_user_free(glyph_run.ctrl_boxes);
275 MIDL_user_free(glyph_run.black_boxes);
277 if (b_ret)
278 return TRUE;
280 fail_safe_text_out:
281 return ExtTextOutW(hdc, x, y, options, lprect, lpString, c, lpDx);
284 int WINAPI DrawTextExA_hook(HDC hdc, LPSTR lpchText, int cchText, LPRECT lprc, UINT format, LPDRAWTEXTPARAMS lpdtp)
286 // DrawTextA calls DrawTextExA eventually
288 const int i_ret = DrawTextExA(hdc, lpchText, cchText, lprc, format, lpdtp);
290 return i_ret;
293 int WINAPI DrawTextExW_hook(HDC hdc, LPWSTR lpchText, int cchText, LPRECT lprc, UINT format, LPDRAWTEXTPARAMS lpdtp)
295 // DrawTextW calls DrawTextExW eventually
297 const int i_ret = DrawTextExW(hdc, lpchText, cchText, lprc, format, lpdtp);
299 return i_ret;
302 bool get_text_extent(HDC hdc, LPCWSTR lpString, int count, LPSIZE lpSize, bool is_glyph_index, int nMaxExtent, LPINT lpnFit, LPINT lpnDx)
304 /*bool b_ret;
306 if (lpString == NULL || lpSize == NULL || count == 0)
307 return false;
309 if (!is_valid_dc(hdc))
310 return false;
312 #ifdef _DEBUG
313 if (!is_target_text(hdc, is_glyph_index, lpString, 0, debug_text, 0))
314 return false;
315 #endif // _DEBUG
317 dc_context context;
318 if (!context.init(hdc))
319 return false;
321 FT_Render_Mode render_mode;
322 if (!get_render_mode(context.setting_cache, context.bmp_header.biBitCount, context.log_font.lfQuality, render_mode))
324 if (!get_render_mode(context.setting_cache, GetDeviceCaps(hdc, BITSPIXEL), context.log_font.lfQuality, render_mode))
325 return false;
328 glyph_run a_glyph_run;
329 GLYPH_CACHE_LEVEL cache_level;
330 b_ret = fetch_glyph_run(is_glyph_index, false, lpString, count, NULL, context, render_mode, a_glyph_run, cache_level);
331 if (!b_ret)
332 return false;
334 if (cache_level < GLYPH_RUN)
335 return false;
337 if (lpSize != NULL)
339 lpSize->cx = get_glyph_run_width(&a_glyph_run, true);
340 lpSize->cy = context.outline_metrics->otmTextMetrics.tmHeight;
343 // for GetTextExtentExPoint series
344 if (lpnFit != NULL || lpnDx != NULL)
346 std::list<RECT>::const_iterator box_iter;
347 INT curr_index;
348 for (box_iter = a_glyph_run.ctrl_boxes.begin(), curr_index = 0; box_iter != a_glyph_run.ctrl_boxes.end(); ++box_iter, ++curr_index)
350 if (lpnFit != NULL && box_iter->right <= nMaxExtent)
351 *lpnFit = curr_index + 1;
353 if (lpnDx != NULL)
354 lpnDx[curr_index] = box_iter->right - a_glyph_run.ctrl_boxes.front().left;
358 return true;
361 BOOL APIENTRY GetTextExtentPoint32A_hook(HDC hdc, LPCSTR lpString, int c, LPSIZE lpSize)
363 std::wstring wide_char_str;
364 if (mb_to_wc(lpString, c, wide_char_str))
366 if (get_text_extent(hdc, wide_char_str.c_str(), static_cast<int>(wide_char_str.size()), lpSize, false))
367 return TRUE;
370 return GetTextExtentPoint32A(hdc, lpString, c, lpSize);
373 BOOL APIENTRY GetTextExtentPoint32W_hook(HDC hdc, LPCWSTR lpString, int c, LPSIZE lpSize)
375 if (get_text_extent(hdc, lpString, c, lpSize, false))
376 return TRUE;
377 else
378 return GetTextExtentPoint32W(hdc, lpString, c, lpSize);
381 BOOL WINAPI GetTextExtentPointI_hook(HDC hdc, LPWORD pgiIn, int cgi, LPSIZE lpSize)
383 if (get_text_extent(hdc, reinterpret_cast<LPCWSTR>(pgiIn), cgi, lpSize, true))
384 return TRUE;
385 else
386 return GetTextExtentPointI(hdc, pgiIn, cgi, lpSize);
389 BOOL APIENTRY GetTextExtentExPointA_hook(HDC hdc, LPCSTR lpszString, int cchString, int nMaxExtent, LPINT lpnFit, LPINT lpnDx, LPSIZE lpSize)
391 std::wstring wide_char_str;
392 if (mb_to_wc(lpszString, cchString, wide_char_str))
394 if (get_text_extent(hdc, wide_char_str.c_str(), static_cast<int>(wide_char_str.size()), lpSize, false, nMaxExtent, lpnFit, lpnDx))
395 return TRUE;
398 return GetTextExtentExPointA(hdc, lpszString, cchString, nMaxExtent, lpnFit, lpnDx, lpSize);
401 BOOL APIENTRY GetTextExtentExPointW_hook(HDC hdc, LPCWSTR lpszString, int cchString, int nMaxExtent, LPINT lpnFit, LPINT lpnDx, LPSIZE lpSize)
403 if (get_text_extent(hdc, lpszString, cchString, lpSize, false, nMaxExtent, lpnFit, lpnDx))
404 return TRUE;
405 else
406 return GetTextExtentExPointW(hdc, lpszString, cchString, nMaxExtent, lpnFit, lpnDx, lpSize);
409 BOOL WINAPI GetTextExtentExPointI_hook(HDC hdc, LPWORD lpwszString, int cwchString, int nMaxExtent, LPINT lpnFit, LPINT lpnDx, LPSIZE lpSize)
411 if (get_text_extent(hdc, reinterpret_cast<LPCWSTR>(lpwszString), cwchString, lpSize, true, nMaxExtent, lpnFit, lpnDx))
412 return TRUE;
413 else
414 return GetTextExtentExPointI(hdc, lpwszString, cwchString, nMaxExtent, lpnFit, lpnDx, lpSize);
417 void adjust_ggo_metrics(const dc_context *context, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, CONST MAT2 *lpmat2)
419 /*bool b_ret;
421 const MAT2 identity_mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
422 if (memcmp(lpmat2, &identity_mat, sizeof(MAT2)) != 0)
424 // current not support transformation matrices other than identity
425 return;
428 ft_renderer ft_renderer;
429 FT_OutlineGlyph target_glyph = NULL;
431 b_ret = ft_renderer.begin(context, FT_RENDER_MODE_NORMAL);
432 if (!b_ret)
433 return;
435 target_glyph = ft_renderer.get_outline_glyph(uChar, !!(fuFormat & GGO_GLYPH_INDEX));
436 ft_renderer.end();
438 if (target_glyph == NULL)
439 return;
441 FT_BBox glyph_bbox;
442 FT_Outline_Get_CBox(&target_glyph->outline, &glyph_bbox);
444 lpgm->gmBlackBoxX = int_from_26dot6(glyph_bbox.xMax - glyph_bbox.xMin);
445 lpgm->gmBlackBoxY = int_from_26dot6(glyph_bbox.yMax - glyph_bbox.yMin);
446 lpgm->gmptGlyphOrigin.x = int_from_26dot6(glyph_bbox.xMin);
447 lpgm->gmptGlyphOrigin.y = int_from_26dot6(glyph_bbox.yMax);
448 lpgm->gmCellIncX = static_cast<short>(int_from_16dot16(target_glyph->root.advance.x));
449 lpgm->gmCellIncY = static_cast<short>(int_from_16dot16(target_glyph->root.advance.y));*/
452 DWORD WINAPI GetGlyphOutlineA_hook(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, DWORD cjBuffer, LPVOID pvBuffer, CONST MAT2 *lpmat2)
454 /*const DWORD ggo_ret = GetGlyphOutlineA(hdc, uChar, fuFormat, lpgm, cjBuffer, pvBuffer, lpmat2);
455 if (ggo_ret == GDI_ERROR)
456 return ggo_ret;
458 if (!!(fuFormat & (GGO_BITMAP | GGO_NATIVE)))
460 // do not adjust metrics if not only the glyph metrics are requested
461 return ggo_ret;
464 if (!is_valid_dc(hdc))
465 return ggo_ret;
467 dc_context context;
468 if (!context.init(hdc))
469 return ggo_ret;
471 if (context.setting_cache->renderer != RENDERER_FREETYPE)
472 return ggo_ret;
474 adjust_ggo_metrics(&context, uChar, fuFormat, lpgm, lpmat2);
476 return ggo_ret;*/
477 return 0;
480 DWORD WINAPI GetGlyphOutlineW_hook(HDC hdc, UINT uChar, UINT fuFormat, LPGLYPHMETRICS lpgm, DWORD cjBuffer, LPVOID pvBuffer, CONST MAT2 *lpmat2)
482 /*const DWORD ggo_ret = GetGlyphOutlineW(hdc, uChar, fuFormat, lpgm, cjBuffer, pvBuffer, lpmat2);
483 if (ggo_ret == GDI_ERROR)
484 return ggo_ret;
486 #ifdef _DEBUG
487 if (!is_target_text(hdc, !!(fuFormat & GGO_GLYPH_INDEX), reinterpret_cast<wchar_t *>(&uChar), 1, debug_text, 0))
488 return ggo_ret;
489 #endif // _DEBUG
491 if (!!(fuFormat & (GGO_BITMAP | GGO_NATIVE)))
492 return ggo_ret;
494 const MAT2 identity_mat = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
495 if (memcmp(lpmat2, &identity_mat, sizeof(MAT2)) != 0)
497 // do not adjust if the transformation matrix is not identical
498 return ggo_ret;
501 if (!is_valid_dc(hdc))
502 return ggo_ret;
504 dc_context context;
505 if (!context.init(hdc))
506 return ggo_ret;
508 if (context.setting_cache->renderer != RENDERER_FREETYPE)
509 return ggo_ret;
511 adjust_ggo_metrics(&context, uChar, fuFormat, lpgm, lpmat2);
513 return ggo_ret;*/
514 return 0;
517 BOOL WINAPI AbortPath_hook(HDC hdc)
519 BOOL b_ret = AbortPath(hdc);
520 if (b_ret)
521 hdc_in_path.erase(hdc);
523 return b_ret;
526 BOOL WINAPI BeginPath_hook(HDC hdc)
528 BOOL b_ret = BeginPath(hdc);
529 if (b_ret)
530 hdc_in_path.insert(hdc);
532 return b_ret;
535 BOOL WINAPI EndPath_hook(HDC hdc)
537 BOOL b_ret = EndPath(hdc);
538 if (b_ret)
539 hdc_in_path.erase(hdc);
541 return b_ret;
544 HRESULT WINAPI ScriptPlace_hook(
545 HDC hdc, // In Optional (see under caching)
546 SCRIPT_CACHE *psc, // InOut Cache handle
547 const WORD *pwGlyphs, // In Glyph buffer from prior ScriptShape call
548 int cGlyphs, // In Number of glyphs
549 const SCRIPT_VISATTR *psva, // In Visual glyph attributes
550 SCRIPT_ANALYSIS *psa, // InOut Result of ScriptItemize (may have fNoGlyphIndex set)
551 int *piAdvance, // Out Advance wdiths
552 GOFFSET *pGoffset, // Out x,y offset for combining glyph
553 ABC *pABC) // Out Composite ABC for the whole run (Optional)
555 SIZE text_extent;
556 if (!get_text_extent(hdc, reinterpret_cast<LPCWSTR>(pwGlyphs), cGlyphs, (pABC == NULL ? NULL : &text_extent), !psa->fNoGlyphIndex, NULL, NULL, piAdvance))
557 return ScriptPlace(hdc, psc, pwGlyphs, cGlyphs, psva, psa, piAdvance, pGoffset, pABC);
559 int width_adjust = 0;
560 if (piAdvance != NULL)
562 for (int i = cGlyphs - 1; i >= 0; i--)
564 if (i != 0)
565 piAdvance[i] -= piAdvance[i - 1];
567 if (psva[i].fZeroWidth)
569 width_adjust += -piAdvance[i];
570 piAdvance[i] = 0;
575 // not support the offset for combining glyphs
576 ZeroMemory(pGoffset, sizeof(GOFFSET) * cGlyphs);
578 if (pABC != NULL)
580 pABC->abcA = 0;
581 pABC->abcB = text_extent.cx + width_adjust;
582 pABC->abcC = 0;
585 return S_OK;
588 #if defined GDIPP_INJECT_SANDBOX && !defined _M_X64
590 void inject_at_eip(LPPROCESS_INFORMATION lpProcessInformation)
592 BOOL b_ret;
593 DWORD dw_ret;
595 // alloc buffer for the injection data
596 // the minimum allocation unit is page
597 SYSTEM_INFO sys_info;
598 GetSystemInfo(&sys_info);
599 BYTE *inject_buffer = new BYTE[sys_info.dwPageSize];
600 memset(inject_buffer, 0xcc, sys_info.dwPageSize);
602 // put gdimm path at the end of the buffer, leave space at the beginning for code
603 const DWORD path_offset = sys_info.dwPageSize - MAX_PATH * sizeof(wchar_t);
604 dw_ret = GetModuleFileNameW(h_self, reinterpret_cast<wchar_t *>(inject_buffer + path_offset), MAX_PATH);
605 assert(dw_ret != 0);
607 // get eip of the spawned thread
608 CONTEXT ctx = {};
609 ctx.ContextFlags = CONTEXT_CONTROL;
610 b_ret = GetThreadContext(lpProcessInformation->hThread, &ctx);
611 assert(b_ret);
613 LPVOID inject_base = VirtualAllocEx(lpProcessInformation->hProcess, NULL, sys_info.dwPageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
614 assert(inject_base != NULL);
616 register BYTE *p = inject_buffer;
618 #define emit_(t, x) *reinterpret_cast<t* UNALIGNED>(p) = (t)(x); p += sizeof(t)
619 #define emit_db(b) emit_(BYTE, b)
620 #define emit_dw(w) emit_(WORD, w)
621 #define emit_dd(d) emit_(DWORD, d)
623 emit_db(0x50); // push eax
625 emit_db(0x68); // push gdimm_path
626 emit_dd((DWORD) inject_base + path_offset);
627 emit_db(0xB8); // mov eax, LoadLibraryW
628 emit_dd(LoadLibraryW);
629 emit_dw(0xD0FF); // call eax
631 emit_db(0x58); // pop eax -> LoadLibraryW has return value
633 emit_db(0x68); // push original_eip
634 emit_dd(ctx.Eip);
635 emit_db(0xC3); // retn -> serve as an absolute jmp
637 // write injection data to target process space
638 b_ret = WriteProcessMemory(lpProcessInformation->hProcess, inject_base, inject_buffer, sys_info.dwPageSize, NULL);
639 assert(b_ret);
641 delete[] inject_buffer;
643 // notify code change
644 b_ret = FlushInstructionCache(lpProcessInformation->hProcess, inject_base, sys_info.dwPageSize);
645 assert(b_ret);
647 // set eip to the entry point of the injection code
648 ctx.Eip = reinterpret_cast<DWORD>(inject_base);
649 b_ret = SetThreadContext(lpProcessInformation->hThread, &ctx);
650 assert(b_ret);
653 BOOL
654 WINAPI
655 CreateProcessAsUserW_hook(
656 HANDLE hToken,
657 LPCWSTR lpApplicationName,
658 LPWSTR lpCommandLine,
659 LPSECURITY_ATTRIBUTES lpProcessAttributes,
660 LPSECURITY_ATTRIBUTES lpThreadAttributes,
661 BOOL bInheritHandles,
662 DWORD dwCreationFlags,
663 LPVOID lpEnvironment,
664 LPCWSTR lpCurrentDirectory,
665 LPSTARTUPINFOW lpStartupInfo,
666 LPPROCESS_INFORMATION lpProcessInformation)
668 // if the token is not restricted, redirect the call to original API
669 // service can inject
670 if (!IsTokenRestricted(hToken))
672 return CreateProcessAsUserW(
673 hToken,
674 lpApplicationName,
675 lpCommandLine,
676 lpProcessAttributes,
677 lpThreadAttributes,
678 bInheritHandles,
679 dwCreationFlags,
680 lpEnvironment,
681 lpCurrentDirectory,
682 lpStartupInfo,
683 lpProcessInformation);
686 // otherwise, the spawned process is restricted, and service cannot inject
688 // injection at EIP requires the process be suspended
689 // if CREATE_SUSPENDED is not specified in the creation flag, remember to resume process after injection
690 bool is_suspended;
691 if (dwCreationFlags & CREATE_SUSPENDED)
692 is_suspended = true;
693 else
695 is_suspended = false;
696 dwCreationFlags |= CREATE_SUSPENDED;
699 if (!CreateProcessAsUserW(
700 hToken,
701 lpApplicationName,
702 lpCommandLine,
703 lpProcessAttributes,
704 lpThreadAttributes,
705 bInheritHandles,
706 dwCreationFlags,
707 lpEnvironment,
708 lpCurrentDirectory,
709 lpStartupInfo,
710 lpProcessInformation))
711 return FALSE;
713 // since the spawned process can be restricted, EasyHook may not work
714 // we inject LoadLibrary call at the entry point of the spawned thread
715 inject_at_eip(lpProcessInformation);
717 if (!is_suspended)
719 DWORD dw_ret = ResumeThread(lpProcessInformation->hThread);
720 assert(dw_ret != -1);
723 return TRUE;
726 #endif // GDIPP_INJECT_SANDBOX && !_M_X64
728 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter_hook(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
730 return NULL;