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

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:
2026-08-02 09:19:42 +08:00
parent 71091e38a9
commit 9451bef753
7 changed files with 65 additions and 155 deletions

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "jiangchang-platform-kit" name = "jiangchang-platform-kit"
version = "1.2.3" version = "1.2.4"
description = "匠厂平台共享组件:Skill 实体 SDK + 桌面应用自动化 SDK + 桌面 UIA 暖树" description = "匠厂平台共享组件:Skill 实体 SDK + 桌面应用自动化 SDK + 桌面 UIA 暖树"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -1,6 +1,7 @@
# jiangchang_desktop_wake 验收(阶段 A:ensure 主路径) # jiangchang_desktop_wake 验收(ensure 主路径,1.2.4+)
正式对外路径是 **`ensure`**(内部:`activate` → `desktop-wake --mode n2-wake` → `probe`)。 正式对外路径是 **`ensure`**(内部:`activate` → `desktop-wake --mode n2-wake` → `probe`)。
`n2-wake` **不再**在企微进程内跑 UIAutomation FindAll(防 `uiautomationcore.dll` 崩溃);判暖只看进程外 probe。
`c2` / `inject` 仅诊断用。 `c2` / `inject` 仅诊断用。
## 0. 编译(企微先完全退出,含托盘) ## 0. 编译(企微先完全退出,含托盘)
@@ -56,8 +57,9 @@ python -m jiangchang_desktop_wake probe --profile wecom
| `probe_after.findall_count` | **≥ 80**(常见 300+) | | `probe_after.findall_count` | **≥ 80**(常见 300+) |
| markers | 含 `con_op`、`searchedit` | | markers | 含 `con_op`、`searchedit` |
| 企微 UI | 可点,无「未响应」 | | 企微 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` | | subclass | `method=SetWindowLongPtr`,`ok=1`,`userdata≠0` |
| 企微进程 | **不崩**、无「错误报告」对话框 |
### 失败时 ### 失败时

View File

@@ -3,7 +3,7 @@
桌面 UIA Provider **暖树**(与 `jiangchang_skill_core` / `jiangchang_desktop_sdk` 平级)。 桌面 UIA Provider **暖树**(与 `jiangchang_skill_core` / `jiangchang_desktop_sdk` 平级)。
企微主路径:注入 `wecom_wake.dll`,对主窗 `SetWindowLongPtr` 后走 DuiLib 企微主路径:注入 `wecom_wake.dll`,对主窗 `SetWindowLongPtr` 后走 DuiLib
`GetAccessible` / `OnGetObject`(已验收冷树 findall 2→300+)。 `GetAccessible` / `OnGetObject`;**不在进程内 FindAll**(1.2.4+,避免 uiautomationcore 崩溃)。
可整目录删除:`src/jiangchang_desktop_wake` + `tests/desktop_wake`。 可整目录删除:`src/jiangchang_desktop_wake` + `tests/desktop_wake`。

View File

@@ -6,23 +6,20 @@
* WakeTarget — 旧子类化(危险,仅 n2-hook) * WakeTarget — 旧子类化(危险,仅 n2-hook)
* JcCallWndProc — 旧钩子(危险,仅 n2-hook) * JcCallWndProc — 旧钩子(危险,仅 n2-hook)
* *
* C2+ 主路径: * 1.2.4 主路径(防 uiautomationcore 崩):
* 1) STA 工作线程 + 进程内 UIA(保持客户端) * - SetWindowLongPtr 子类化,WM_GETOBJECT → DuiLib GetAccessible/OnGetObject
* 2) SetWindowSubclass:WM_GETOBJECT 时走 DuiLib 已导出的 * - 重入守卫:处理 GETOBJECT 时不再二次进 DuiLib
* GetAccessible / OnGetObject(不挂钩、不用 CreateStdAccessibleObject) * - 不做进程内 UIAutomation FindAll / AccessibleObjectFromWindow(判暖交给进程外 probe)
*/ */
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
#include <oleacc.h> #include <oleacc.h>
#include <UIAutomationClient.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#pragma comment(lib, "oleacc.lib") #pragma comment(lib, "oleacc.lib")
#pragma comment(lib, "ole32.lib") #pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "uuid.lib")
#pragma comment(lib, "user32.lib") #pragma comment(lib, "user32.lib")
#pragma comment(lib, "comctl32.lib") #pragma comment(lib, "comctl32.lib")
@@ -35,9 +32,6 @@
#ifndef CHILDID_SELF #ifndef CHILDID_SELF
#define CHILDID_SELF 0 #define CHILDID_SELF 0
#endif #endif
#ifndef ANR_ON
#define ANR_ON 0x00000001
#endif
#ifndef UiaRootObjectId #ifndef UiaRootObjectId
#define UiaRootObjectId ((LONG)0xFFFFFFE7) #define UiaRootObjectId ((LONG)0xFFFFFFE7)
#endif #endif
@@ -49,23 +43,21 @@
static HMODULE g_self = NULL; static HMODULE g_self = NULL;
static HWND g_hwnd = NULL; static HWND g_hwnd = NULL;
static WNDPROC g_oldProc = NULL; static WNDPROC g_oldProc = NULL;
static WNDPROC g_duiOldProc = NULL;
static volatile LONG g_getobjectHits = 0; static volatile LONG g_getobjectHits = 0;
static volatile LONG g_hookHits = 0; static volatile LONG g_hookHits = 0;
static volatile LONG g_duiHits = 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_staThread = NULL;
static HANDLE g_staReady = NULL; static HANDLE g_staReady = NULL;
static HWND g_msgHwnd = NULL; static HWND g_msgHwnd = NULL;
static volatile LONG g_staStarted = 0; static volatile LONG g_staStarted = 0;
static IUIAutomation* g_auto = NULL; /* per-thread reentrancy guard for WM_GETOBJECT */
static IUIAutomationElement* g_root = NULL; static __declspec(thread) int t_inGetObject = 0;
static IUIAutomationElementArray* g_arr = NULL;
static IAccessible* g_acc = NULL;
static volatile LONG g_subclassInstalled = 0;
/* DuiLib thiscall helpers (x86) */
typedef IAccessible*(__thiscall* FnGetAccessible)(void* self); typedef IAccessible*(__thiscall* FnGetAccessible)(void* self);
typedef LRESULT(__thiscall* FnOnGetObject)( typedef LRESULT(__thiscall* FnOnGetObject)(
void* self, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* bHandled); 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); 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() static bool ResolveDuiLib()
{ {
if (g_fnGetAccessible && g_fnOnGetObject) return true; if (g_fnGetAccessible && g_fnOnGetObject) return true;
@@ -171,7 +144,6 @@ static bool ResolveDuiLib()
return g_fnGetAccessible != NULL || g_fnOnGetObject != NULL; 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) static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
{ {
if (!ResolveDuiLib()) if (!ResolveDuiLib())
@@ -194,7 +166,6 @@ static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
IAccessible* acc = g_fnGetAccessible(self); IAccessible* acc = g_fnGetAccessible(self);
if (acc) { if (acc) {
LRESULT lr = LresultFromObject(IID_IAccessible, wParam, (LPUNKNOWN)acc); LRESULT lr = LresultFromObject(IID_IAccessible, wParam, (LPUNKNOWN)acc);
/* LresultFromObject AddRef's; release our ref from GetAccessible */
acc->Release(); acc->Release();
return lr; return lr;
} }
@@ -202,7 +173,33 @@ static LRESULT TryDuiLibGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam)
return 0; 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( static LRESULT CALLBACK DuiSubclassProc(
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
@@ -210,34 +207,15 @@ static LRESULT CALLBACK DuiSubclassProc(
{ {
(void)uIdSubclass; (void)uIdSubclass;
(void)dwRefData; (void)dwRefData;
if (uMsg == WM_GETOBJECT) { if (uMsg == WM_GETOBJECT)
InterlockedIncrement(&g_getobjectHits); return HandleGetObject(hWnd, wParam, lParam, NULL, true);
LRESULT r = DefSubclassProc(hWnd, uMsg, wParam, lParam);
if (r != 0)
return r;
r = TryDuiLibGetObject(hWnd, wParam, lParam);
if (r != 0)
return r;
return 0;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam); 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) static LRESULT CALLBACK DuiWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
if (msg == WM_GETOBJECT) { if (msg == WM_GETOBJECT)
InterlockedIncrement(&g_getobjectHits); return HandleGetObject(hwnd, wParam, lParam, g_duiOldProc, false);
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 (g_duiOldProc) if (g_duiOldProc)
return CallWindowProcW(g_duiOldProc, hwnd, msg, wParam, lParam); return CallWindowProcW(g_duiOldProc, hwnd, msg, wParam, lParam);
return DefWindowProcW(hwnd, msg, wParam, lParam); return DefWindowProcW(hwnd, msg, wParam, lParam);
@@ -251,21 +229,7 @@ static bool InstallDuiSubclass(HWND hwnd)
ResolveDuiLib(); ResolveDuiLib();
void* userdata = (void*)GetWindowLongPtrW(hwnd, GWLP_USERDATA); 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); SetLastError(0);
g_duiOldProc = (WNDPROC)SetWindowLongPtrW( g_duiOldProc = (WNDPROC)SetWindowLongPtrW(
hwnd, GWLP_WNDPROC, (LONG_PTR)DuiWndProc); hwnd, GWLP_WNDPROC, (LONG_PTR)DuiWndProc);
@@ -288,10 +252,9 @@ static bool InstallDuiSubclass(HWND hwnd)
char line[512]; char line[512];
sprintf_s(line, sprintf_s(line,
"hwnd=%p ok=%d gle=%lu method=%s userdata=%p " "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, hwnd, (int)ok, gle, method, userdata,
(void*)accPtr, (long)ongetLr, g_duilib, g_duilib, g_fnGetAccessible, g_fnOnGetObject);
g_fnGetAccessible, g_fnOnGetObject);
WriteMarker("jiangchang_desktop_wake_subclass.txt", line); WriteMarker("jiangchang_desktop_wake_subclass.txt", line);
if (!ok) { if (!ok) {
InterlockedExchange(&g_subclassInstalled, 0); InterlockedExchange(&g_subclassInstalled, 0);
@@ -300,78 +263,35 @@ static bool InstallDuiSubclass(HWND hwnd)
return true; return true;
} }
static void DoInProcessUiaWake(HWND hwnd) /* 只装子类化 + 异步 nudge;可选一次短超时 GETOBJECT 看 lr(无进程内 UIA) */
static void DoSafeWake(HWND hwnd)
{ {
char line[1024]; char line[512];
LONG findall = -1;
LONG msaaKids = -1;
HRESULT hrAuto = E_FAIL;
HRESULT hrEl = E_FAIL;
HRESULT hrFind = E_FAIL;
HRESULT hrMsaa = E_FAIL;
LRESULT lrClient = 0; LRESULT lrClient = 0;
LRESULT lrUia = 0;
int subclass_ok = 0; int subclass_ok = 0;
int dui_ok = 0; int dui_ok = 0;
TryAccUtilityState(hwnd);
ResolveDuiLib(); ResolveDuiLib();
dui_ok = (g_fnGetAccessible || g_fnOnGetObject) ? 1 : 0; dui_ok = (g_fnGetAccessible || g_fnOnGetObject) ? 1 : 0;
subclass_ok = InstallDuiSubclass(hwnd) ? 1 : 0; subclass_ok = InstallDuiSubclass(hwnd) ? 1 : 0;
NudgeWinEvents(hwnd); NudgeWinEvents(hwnd);
/* Sync probe WM_GETOBJECT after subclass — goes through our handler */ DWORD_PTR smResult = 0;
lrClient = SendMessageW(hwnd, WM_GETOBJECT, 0, (LPARAM)OBJID_CLIENT); if (SendMessageTimeoutW(
lrUia = SendMessageW(hwnd, WM_GETOBJECT, 0, (LPARAM)UiaRootObjectId); hwnd, WM_GETOBJECT, 0, (LPARAM)OBJID_CLIENT,
SMTO_ABORTIFHUNG, 2000, &smResult)) {
ReleaseKeepAlive(); lrClient = (LRESULT)smResult;
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;
}
} }
NudgeWinEvents(hwnd); NudgeWinEvents(hwnd);
sprintf_s(line, sprintf_s(line,
"hwnd=%p sta_tid=%lu findall=%ld msaa_kids=%ld " "hwnd=%p sta_tid=%lu lr_client=%ld subclass=%d dui=%d "
"lr_client=%ld lr_uia=%ld subclass=%d dui=%d " "dui_hits=%ld getobject_hits=%ld reenter_skip=%ld "
"dui_hits=%ld getobject_hits=%ld " "no_inproc_uia=1 done=1\r\n",
"hr_auto=0x%08lx hr_el=0x%08lx hr_find=0x%08lx hr_msaa=0x%08lx " hwnd, GetCurrentThreadId(), (long)lrClient, subclass_ok, dui_ok,
"keep_auto=%d keep_root=%d keep_arr=%d keep_acc=%d done=1\r\n", (long)g_duiHits, (long)g_getobjectHits, (long)g_reenterSkip);
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);
WriteMarker("jiangchang_desktop_wake_provider.txt", line); 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) { if (msg == WM_JC_WAKE) {
HWND target = (HWND)wParam; HWND target = (HWND)wParam;
if (target && IsWindow(target)) if (target && IsWindow(target))
DoInProcessUiaWake(target); DoSafeWake(target);
else else
WriteMarker("jiangchang_desktop_wake_provider.txt", "err=bad_hwnd done=1\r\n"); WriteMarker("jiangchang_desktop_wake_provider.txt", "err=bad_hwnd done=1\r\n");
return 0; return 0;
@@ -394,9 +314,6 @@ static LRESULT CALLBACK MsgWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
static DWORD WINAPI StaThreadProc(LPVOID) static DWORD WINAPI StaThreadProc(LPVOID)
{ {
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
bool needUninit = SUCCEEDED(hr) || hr == S_FALSE;
WNDCLASSW wc; WNDCLASSW wc;
ZeroMemory(&wc, sizeof(wc)); ZeroMemory(&wc, sizeof(wc));
wc.lpfnWndProc = MsgWndProc; wc.lpfnWndProc = MsgWndProc;
@@ -413,7 +330,6 @@ static DWORD WINAPI StaThreadProc(LPVOID)
if (!g_msgHwnd) { if (!g_msgHwnd) {
WriteMarker("jiangchang_desktop_wake_provider.txt", "err=no_msg_hwnd done=1\r\n"); WriteMarker("jiangchang_desktop_wake_provider.txt", "err=no_msg_hwnd done=1\r\n");
if (needUninit) CoUninitialize();
return 1; return 1;
} }
@@ -423,12 +339,10 @@ static DWORD WINAPI StaThreadProc(LPVOID)
DispatchMessageW(&msg); DispatchMessageW(&msg);
} }
ReleaseKeepAlive();
if (g_msgHwnd) { if (g_msgHwnd) {
DestroyWindow(g_msgHwnd); DestroyWindow(g_msgHwnd);
g_msgHwnd = NULL; g_msgHwnd = NULL;
} }
if (needUninit) CoUninitialize();
return 0; return 0;
} }
@@ -475,7 +389,7 @@ extern "C" __declspec(dllexport) DWORD WINAPI WakeProvider(LPVOID param)
DWORD_PTR result = 0; DWORD_PTR result = 0;
LRESULT ok = SendMessageTimeoutW( LRESULT ok = SendMessageTimeoutW(
g_msgHwnd, WM_JC_WAKE, (WPARAM)hwnd, 0, g_msgHwnd, WM_JC_WAKE, (WPARAM)hwnd, 0,
SMTO_ABORTIFHUNG, 15000, &result); SMTO_ABORTIFHUNG, 8000, &result);
if (ok == 0) { if (ok == 0) {
char line[256]; 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) static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
if (msg == WM_GETOBJECT) { if (msg == WM_GETOBJECT) {
InterlockedIncrement(&g_getobjectHits); LRESULT r = HandleGetObject(hwnd, wParam, lParam, g_oldProc, false);
LRESULT r = 0;
if (g_oldProc)
r = CallWindowProcW(g_oldProc, hwnd, msg, wParam, lParam);
if (r != 0)
return r;
r = TryDuiLibGetObject(hwnd, wParam, lParam);
if (r != 0) if (r != 0)
return r; return r;
LONG objId = (LONG)lParam; LONG objId = (LONG)lParam;

View File

@@ -43,7 +43,7 @@ $bat = Join-Path $env:TEMP "jiangchang_build_wecom_wake.bat"
@" @"
@echo off @echo off
call "$vcvars32" || exit /b 1 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% exit /b %ERRORLEVEL%
"@ | Set-Content -Path $bat -Encoding ASCII "@ | Set-Content -Path $bat -Encoding ASCII