fix(desktop-wake): avoid in-process UIA FindAll crash (1.2.4)
All checks were successful
Publish Python Package to Gitea / publish (push) Successful in 27s
All checks were successful
Publish Python Package to Gitea / publish (push) Successful in 27s
Keep DuiLib subclass wake only with GETOBJECT reentrancy guard; let ensure probe warm out-of-process. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jiangchang-platform-kit"
|
||||
version = "1.2.3"
|
||||
version = "1.2.4"
|
||||
description = "匠厂平台共享组件:Skill 实体 SDK + 桌面应用自动化 SDK + 桌面 UIA 暖树"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# jiangchang_desktop_wake 验收(阶段 A:ensure 主路径)
|
||||
# jiangchang_desktop_wake 验收(ensure 主路径,1.2.4+)
|
||||
|
||||
正式对外路径是 **`ensure`**(内部:`activate` → `desktop-wake --mode n2-wake` → `probe`)。
|
||||
`n2-wake` **不再**在企微进程内跑 UIAutomation FindAll(防 `uiautomationcore.dll` 崩溃);判暖只看进程外 probe。
|
||||
`c2` / `inject` 仅诊断用。
|
||||
|
||||
## 0. 编译(企微先完全退出,含托盘)
|
||||
@@ -56,8 +57,9 @@ python -m jiangchang_desktop_wake probe --profile wecom
|
||||
| `probe_after.findall_count` | **≥ 80**(常见 300+) |
|
||||
| markers | 含 `con_op`、`searchedit` |
|
||||
| 企微 UI | 可点,无「未响应」 |
|
||||
| provider | `done=1` `subclass=1` `dui=1` `lr_client≠0` |
|
||||
| provider | `done=1` `subclass=1` `dui=1` `no_inproc_uia=1`;`lr_client≠0` 更佳 |
|
||||
| subclass | `method=SetWindowLongPtr`,`ok=1`,`userdata≠0` |
|
||||
| 企微进程 | **不崩**、无「错误报告」对话框 |
|
||||
|
||||
### 失败时
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
桌面 UIA Provider **暖树**(与 `jiangchang_skill_core` / `jiangchang_desktop_sdk` 平级)。
|
||||
|
||||
企微主路径:注入 `wecom_wake.dll`,对主窗 `SetWindowLongPtr` 后走 DuiLib
|
||||
`GetAccessible` / `OnGetObject`(已验收冷树 findall 2→300+)。
|
||||
`GetAccessible` / `OnGetObject`;**不在进程内 FindAll**(1.2.4+,避免 uiautomationcore 崩溃)。
|
||||
|
||||
可整目录删除:`src/jiangchang_desktop_wake` + `tests/desktop_wake`。
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -6,23 +6,20 @@
|
||||
* WakeTarget — 旧子类化(危险,仅 n2-hook)
|
||||
* JcCallWndProc — 旧钩子(危险,仅 n2-hook)
|
||||
*
|
||||
* C2+ 主路径:
|
||||
* 1) STA 工作线程 + 进程内 UIA(保持客户端)
|
||||
* 2) SetWindowSubclass:WM_GETOBJECT 时走 DuiLib 已导出的
|
||||
* GetAccessible / OnGetObject(不挂钩、不用 CreateStdAccessibleObject)
|
||||
* 1.2.4 主路径(防 uiautomationcore 崩):
|
||||
* - SetWindowLongPtr 子类化,WM_GETOBJECT → DuiLib GetAccessible/OnGetObject
|
||||
* - 重入守卫:处理 GETOBJECT 时不再二次进 DuiLib
|
||||
* - 不做进程内 UIAutomation FindAll / AccessibleObjectFromWindow(判暖交给进程外 probe)
|
||||
*/
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <oleacc.h>
|
||||
#include <UIAutomationClient.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma comment(lib, "oleacc.lib")
|
||||
#pragma comment(lib, "ole32.lib")
|
||||
#pragma comment(lib, "oleaut32.lib")
|
||||
#pragma comment(lib, "uuid.lib")
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
|
||||
@@ -35,9 +32,6 @@
|
||||
#ifndef CHILDID_SELF
|
||||
#define CHILDID_SELF 0
|
||||
#endif
|
||||
#ifndef ANR_ON
|
||||
#define ANR_ON 0x00000001
|
||||
#endif
|
||||
#ifndef UiaRootObjectId
|
||||
#define UiaRootObjectId ((LONG)0xFFFFFFE7)
|
||||
#endif
|
||||
@@ -49,23 +43,21 @@
|
||||
static HMODULE g_self = NULL;
|
||||
static HWND g_hwnd = NULL;
|
||||
static WNDPROC g_oldProc = NULL;
|
||||
static WNDPROC g_duiOldProc = NULL;
|
||||
static volatile LONG g_getobjectHits = 0;
|
||||
static volatile LONG g_hookHits = 0;
|
||||
static volatile LONG g_duiHits = 0;
|
||||
static volatile LONG g_reenterSkip = 0;
|
||||
static volatile LONG g_subclassInstalled = 0;
|
||||
|
||||
static HANDLE g_staThread = NULL;
|
||||
static HANDLE g_staReady = NULL;
|
||||
static HWND g_msgHwnd = NULL;
|
||||
static volatile LONG g_staStarted = 0;
|
||||
|
||||
static IUIAutomation* g_auto = NULL;
|
||||
static IUIAutomationElement* g_root = NULL;
|
||||
static IUIAutomationElementArray* g_arr = NULL;
|
||||
static IAccessible* g_acc = NULL;
|
||||
/* per-thread reentrancy guard for WM_GETOBJECT */
|
||||
static __declspec(thread) int t_inGetObject = 0;
|
||||
|
||||
static volatile LONG g_subclassInstalled = 0;
|
||||
|
||||
/* DuiLib thiscall helpers (x86) */
|
||||
typedef IAccessible*(__thiscall* FnGetAccessible)(void* self);
|
||||
typedef LRESULT(__thiscall* FnOnGetObject)(
|
||||
void* self, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* bHandled);
|
||||
@@ -138,25 +130,6 @@ static void NudgeWinEvents(HWND hwnd)
|
||||
PostMessageW(hwnd, WM_NULL, 0, 0);
|
||||
}
|
||||
|
||||
static void TryAccUtilityState(HWND hwnd)
|
||||
{
|
||||
HMODULE oleacc = GetModuleHandleW(L"oleacc.dll");
|
||||
if (!oleacc) oleacc = LoadLibraryW(L"oleacc.dll");
|
||||
if (!oleacc) return;
|
||||
typedef HRESULT(WINAPI* PFN)(HWND, DWORD, DWORD);
|
||||
PFN fn = (PFN)GetProcAddress(oleacc, "AccSetRunningUtilityState");
|
||||
if (!fn) return;
|
||||
fn(hwnd, ANR_ON, ANR_ON);
|
||||
}
|
||||
|
||||
static void ReleaseKeepAlive()
|
||||
{
|
||||
if (g_arr) { g_arr->Release(); g_arr = NULL; }
|
||||
if (g_root) { g_root->Release(); g_root = NULL; }
|
||||
if (g_auto) { g_auto->Release(); g_auto = NULL; }
|
||||
if (g_acc) { g_acc->Release(); g_acc = NULL; }
|
||||
}
|
||||
|
||||
static bool ResolveDuiLib()
|
||||
{
|
||||
if (g_fnGetAccessible && g_fnOnGetObject) return true;
|
||||
@@ -171,7 +144,6 @@ static bool ResolveDuiLib()
|
||||
return g_fnGetAccessible != NULL || g_fnOnGetObject != NULL;
|
||||
}
|
||||
|
||||
/* Force DuiLib MSAA for WM_GETOBJECT — no CreateStdAccessibleObject (avoids UI hang). */
|
||||
static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (!ResolveDuiLib())
|
||||
@@ -194,7 +166,6 @@ static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
IAccessible* acc = g_fnGetAccessible(self);
|
||||
if (acc) {
|
||||
LRESULT lr = LresultFromObject(IID_IAccessible, wParam, (LPUNKNOWN)acc);
|
||||
/* LresultFromObject AddRef's; release our ref from GetAccessible */
|
||||
acc->Release();
|
||||
return lr;
|
||||
}
|
||||
@@ -202,7 +173,33 @@ static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WNDPROC g_duiOldProc = NULL;
|
||||
static LRESULT HandleGetObject(
|
||||
HWND hwnd, WPARAM wParam, LPARAM lParam, WNDPROC oldProc, bool useDefSubclass)
|
||||
{
|
||||
InterlockedIncrement(&g_getobjectHits);
|
||||
|
||||
if (t_inGetObject) {
|
||||
InterlockedIncrement(&g_reenterSkip);
|
||||
if (useDefSubclass)
|
||||
return DefSubclassProc(hwnd, WM_GETOBJECT, wParam, lParam);
|
||||
if (oldProc)
|
||||
return CallWindowProcW(oldProc, hwnd, WM_GETOBJECT, wParam, lParam);
|
||||
return DefWindowProcW(hwnd, WM_GETOBJECT, wParam, lParam);
|
||||
}
|
||||
|
||||
t_inGetObject = 1;
|
||||
LRESULT r = 0;
|
||||
if (useDefSubclass)
|
||||
r = DefSubclassProc(hwnd, WM_GETOBJECT, wParam, lParam);
|
||||
else if (oldProc)
|
||||
r = CallWindowProcW(oldProc, hwnd, WM_GETOBJECT, wParam, lParam);
|
||||
|
||||
if (r == 0)
|
||||
r = TryDuiLibGetObject(hwnd, wParam, lParam);
|
||||
|
||||
t_inGetObject = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK DuiSubclassProc(
|
||||
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
|
||||
@@ -210,34 +207,15 @@ static LRESULT CALLBACK DuiSubclassProc(
|
||||
{
|
||||
(void)uIdSubclass;
|
||||
(void)dwRefData;
|
||||
if (uMsg == WM_GETOBJECT) {
|
||||
InterlockedIncrement(&g_getobjectHits);
|
||||
LRESULT r = DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
if (r != 0)
|
||||
return r;
|
||||
r = TryDuiLibGetObject(hWnd, wParam, lParam);
|
||||
if (r != 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
if (uMsg == WM_GETOBJECT)
|
||||
return HandleGetObject(hWnd, wParam, lParam, NULL, true);
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
/* Fallback when comctl SetWindowSubclass unavailable in host */
|
||||
static LRESULT CALLBACK DuiWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_GETOBJECT) {
|
||||
InterlockedIncrement(&g_getobjectHits);
|
||||
LRESULT r = 0;
|
||||
if (g_duiOldProc)
|
||||
r = CallWindowProcW(g_duiOldProc, hwnd, msg, wParam, lParam);
|
||||
if (r != 0)
|
||||
return r;
|
||||
r = TryDuiLibGetObject(hwnd, wParam, lParam);
|
||||
if (r != 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
if (msg == WM_GETOBJECT)
|
||||
return HandleGetObject(hwnd, wParam, lParam, g_duiOldProc, false);
|
||||
if (g_duiOldProc)
|
||||
return CallWindowProcW(g_duiOldProc, hwnd, msg, wParam, lParam);
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
@@ -251,21 +229,7 @@ static bool InstallDuiSubclass(HWND hwnd)
|
||||
|
||||
ResolveDuiLib();
|
||||
void* userdata = (void*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
|
||||
LONG_PTR accPtr = 0;
|
||||
LONG_PTR ongetLr = 0;
|
||||
if (userdata && g_fnGetAccessible) {
|
||||
IAccessible* acc = g_fnGetAccessible(userdata);
|
||||
accPtr = (LONG_PTR)acc;
|
||||
if (acc) {
|
||||
long kids = -1;
|
||||
acc->get_accChildCount(&kids);
|
||||
ongetLr = kids;
|
||||
/* keep one ref for diagnostics; Release extra if we AddRef'd — GetAccessible owns */
|
||||
acc->Release();
|
||||
}
|
||||
}
|
||||
|
||||
/* 企微进程里 SetWindowSubclass 常失败;主用 SetWindowLongPtr(只转发 DuiLib GetAccessible,不挂钩) */
|
||||
SetLastError(0);
|
||||
g_duiOldProc = (WNDPROC)SetWindowLongPtrW(
|
||||
hwnd, GWLP_WNDPROC, (LONG_PTR)DuiWndProc);
|
||||
@@ -288,10 +252,9 @@ static bool InstallDuiSubclass(HWND hwnd)
|
||||
char line[512];
|
||||
sprintf_s(line,
|
||||
"hwnd=%p ok=%d gle=%lu method=%s userdata=%p "
|
||||
"getacc_ret=%p getacc_kids=%ld duilib=%p getacc=%p onget=%p\r\n",
|
||||
"duilib=%p getacc=%p onget=%p\r\n",
|
||||
hwnd, (int)ok, gle, method, userdata,
|
||||
(void*)accPtr, (long)ongetLr, g_duilib,
|
||||
g_fnGetAccessible, g_fnOnGetObject);
|
||||
g_duilib, g_fnGetAccessible, g_fnOnGetObject);
|
||||
WriteMarker("jiangchang_desktop_wake_subclass.txt", line);
|
||||
if (!ok) {
|
||||
InterlockedExchange(&g_subclassInstalled, 0);
|
||||
@@ -300,78 +263,35 @@ static bool InstallDuiSubclass(HWND hwnd)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DoInProcessUiaWake(HWND hwnd)
|
||||
/* 只装子类化 + 异步 nudge;可选一次短超时 GETOBJECT 看 lr(无进程内 UIA) */
|
||||
static void DoSafeWake(HWND hwnd)
|
||||
{
|
||||
char line[1024];
|
||||
LONG findall = -1;
|
||||
LONG msaaKids = -1;
|
||||
HRESULT hrAuto = E_FAIL;
|
||||
HRESULT hrEl = E_FAIL;
|
||||
HRESULT hrFind = E_FAIL;
|
||||
HRESULT hrMsaa = E_FAIL;
|
||||
char line[512];
|
||||
LRESULT lrClient = 0;
|
||||
LRESULT lrUia = 0;
|
||||
int subclass_ok = 0;
|
||||
int dui_ok = 0;
|
||||
|
||||
TryAccUtilityState(hwnd);
|
||||
ResolveDuiLib();
|
||||
dui_ok = (g_fnGetAccessible || g_fnOnGetObject) ? 1 : 0;
|
||||
subclass_ok = InstallDuiSubclass(hwnd) ? 1 : 0;
|
||||
|
||||
NudgeWinEvents(hwnd);
|
||||
|
||||
/* Sync probe WM_GETOBJECT after subclass — goes through our handler */
|
||||
lrClient = SendMessageW(hwnd, WM_GETOBJECT, 0, (LPARAM)OBJID_CLIENT);
|
||||
lrUia = SendMessageW(hwnd, WM_GETOBJECT, 0, (LPARAM)UiaRootObjectId);
|
||||
|
||||
ReleaseKeepAlive();
|
||||
|
||||
hrAuto = CoCreateInstance(
|
||||
CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_IUIAutomation, (void**)&g_auto);
|
||||
if (SUCCEEDED(hrAuto) && g_auto) {
|
||||
hrEl = g_auto->ElementFromHandle(hwnd, &g_root);
|
||||
if (SUCCEEDED(hrEl) && g_root) {
|
||||
IUIAutomationCondition* cond = NULL;
|
||||
if (SUCCEEDED(g_auto->CreateTrueCondition(&cond)) && cond) {
|
||||
hrFind = g_root->FindAll(TreeScope_Subtree, cond, &g_arr);
|
||||
cond->Release();
|
||||
if (SUCCEEDED(hrFind) && g_arr) {
|
||||
int len = 0;
|
||||
if (SUCCEEDED(g_arr->get_Length(&len)))
|
||||
findall = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
IAccessible* acc = NULL;
|
||||
hrMsaa = AccessibleObjectFromWindow(
|
||||
hwnd, OBJID_CLIENT, IID_IAccessible, (void**)&acc);
|
||||
if (SUCCEEDED(hrMsaa) && acc) {
|
||||
g_acc = acc;
|
||||
long kids = 0;
|
||||
if (SUCCEEDED(acc->get_accChildCount(&kids)))
|
||||
msaaKids = kids;
|
||||
}
|
||||
DWORD_PTR smResult = 0;
|
||||
if (SendMessageTimeoutW(
|
||||
hwnd, WM_GETOBJECT, 0, (LPARAM)OBJID_CLIENT,
|
||||
SMTO_ABORTIFHUNG, 2000, &smResult)) {
|
||||
lrClient = (LRESULT)smResult;
|
||||
}
|
||||
|
||||
NudgeWinEvents(hwnd);
|
||||
|
||||
sprintf_s(line,
|
||||
"hwnd=%p sta_tid=%lu findall=%ld msaa_kids=%ld "
|
||||
"lr_client=%ld lr_uia=%ld subclass=%d dui=%d "
|
||||
"dui_hits=%ld getobject_hits=%ld "
|
||||
"hr_auto=0x%08lx hr_el=0x%08lx hr_find=0x%08lx hr_msaa=0x%08lx "
|
||||
"keep_auto=%d keep_root=%d keep_arr=%d keep_acc=%d done=1\r\n",
|
||||
hwnd, GetCurrentThreadId(), (long)findall, (long)msaaKids,
|
||||
(long)lrClient, (long)lrUia, subclass_ok, dui_ok,
|
||||
(long)g_duiHits, (long)g_getobjectHits,
|
||||
(unsigned long)hrAuto, (unsigned long)hrEl,
|
||||
(unsigned long)hrFind, (unsigned long)hrMsaa,
|
||||
g_auto ? 1 : 0, g_root ? 1 : 0, g_arr ? 1 : 0, g_acc ? 1 : 0);
|
||||
"hwnd=%p sta_tid=%lu lr_client=%ld subclass=%d dui=%d "
|
||||
"dui_hits=%ld getobject_hits=%ld reenter_skip=%ld "
|
||||
"no_inproc_uia=1 done=1\r\n",
|
||||
hwnd, GetCurrentThreadId(), (long)lrClient, subclass_ok, dui_ok,
|
||||
(long)g_duiHits, (long)g_getobjectHits, (long)g_reenterSkip);
|
||||
WriteMarker("jiangchang_desktop_wake_provider.txt", line);
|
||||
}
|
||||
|
||||
@@ -380,7 +300,7 @@ static LRESULT CALLBACK MsgWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||
if (msg == WM_JC_WAKE) {
|
||||
HWND target = (HWND)wParam;
|
||||
if (target && IsWindow(target))
|
||||
DoInProcessUiaWake(target);
|
||||
DoSafeWake(target);
|
||||
else
|
||||
WriteMarker("jiangchang_desktop_wake_provider.txt", "err=bad_hwnd done=1\r\n");
|
||||
return 0;
|
||||
@@ -394,9 +314,6 @@ static LRESULT CALLBACK MsgWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
|
||||
|
||||
static DWORD WINAPI StaThreadProc(LPVOID)
|
||||
{
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
bool needUninit = SUCCEEDED(hr) || hr == S_FALSE;
|
||||
|
||||
WNDCLASSW wc;
|
||||
ZeroMemory(&wc, sizeof(wc));
|
||||
wc.lpfnWndProc = MsgWndProc;
|
||||
@@ -413,7 +330,6 @@ static DWORD WINAPI StaThreadProc(LPVOID)
|
||||
|
||||
if (!g_msgHwnd) {
|
||||
WriteMarker("jiangchang_desktop_wake_provider.txt", "err=no_msg_hwnd done=1\r\n");
|
||||
if (needUninit) CoUninitialize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -423,12 +339,10 @@ static DWORD WINAPI StaThreadProc(LPVOID)
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
|
||||
ReleaseKeepAlive();
|
||||
if (g_msgHwnd) {
|
||||
DestroyWindow(g_msgHwnd);
|
||||
g_msgHwnd = NULL;
|
||||
}
|
||||
if (needUninit) CoUninitialize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -475,7 +389,7 @@ extern "C" __declspec(dllexport) DWORD WINAPI WakeProvider(LPVOID param)
|
||||
DWORD_PTR result = 0;
|
||||
LRESULT ok = SendMessageTimeoutW(
|
||||
g_msgHwnd, WM_JC_WAKE, (WPARAM)hwnd, 0,
|
||||
SMTO_ABORTIFHUNG, 15000, &result);
|
||||
SMTO_ABORTIFHUNG, 8000, &result);
|
||||
|
||||
if (ok == 0) {
|
||||
char line[256];
|
||||
@@ -519,13 +433,7 @@ static LRESULT TryStdAccessible(HWND hwnd, WPARAM wParam, LONG objId)
|
||||
static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_GETOBJECT) {
|
||||
InterlockedIncrement(&g_getobjectHits);
|
||||
LRESULT r = 0;
|
||||
if (g_oldProc)
|
||||
r = CallWindowProcW(g_oldProc, hwnd, msg, wParam, lParam);
|
||||
if (r != 0)
|
||||
return r;
|
||||
r = TryDuiLibGetObject(hwnd, wParam, lParam);
|
||||
LRESULT r = HandleGetObject(hwnd, wParam, lParam, g_oldProc, false);
|
||||
if (r != 0)
|
||||
return r;
|
||||
LONG objId = (LONG)lParam;
|
||||
|
||||
@@ -43,7 +43,7 @@ $bat = Join-Path $env:TEMP "jiangchang_build_wecom_wake.bat"
|
||||
@"
|
||||
@echo off
|
||||
call "$vcvars32" || exit /b 1
|
||||
cl /nologo /LD /O2 /EHsc /DWIN32 /D_WINDOWS /D_USRDLL /utf-8 "$srcCpp" /Fe"$dllTarget" /Fo"$objPath" /link /DEF:"$srcDef" user32.lib ole32.lib oleacc.lib oleaut32.lib uuid.lib comctl32.lib
|
||||
cl /nologo /LD /O2 /EHsc /DWIN32 /D_WINDOWS /D_USRDLL /utf-8 "$srcCpp" /Fe"$dllTarget" /Fo"$objPath" /link /DEF:"$srcDef" user32.lib ole32.lib oleacc.lib comctl32.lib
|
||||
exit /b %ERRORLEVEL%
|
||||
"@ | Set-Content -Path $bat -Encoding ASCII
|
||||
|
||||
|
||||
Reference in New Issue
Block a user