From 9451bef7539e4199309de675844df5c26b1e6d36 Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Sun, 2 Aug 2026 09:19:42 +0800 Subject: [PATCH] fix(desktop-wake): avoid in-process UIA FindAll crash (1.2.4) Keep DuiLib subclass wake only with GETOBJECT reentrancy guard; let ensure probe warm out-of-process. Co-authored-by: Cursor --- pyproject.toml | 2 +- src/jiangchang_desktop_wake/ACCEPTANCE.md | 6 +- src/jiangchang_desktop_wake/README.md | 2 +- .../native/desktop-wake.exe | Bin 18432 -> 18432 bytes .../native/wecom_wake.dll | Bin 119296 -> 118784 bytes .../native_src/N2/payload/wecom_wake.cpp | 208 +++++------------- .../native_src/build.ps1 | 2 +- 7 files changed, 65 insertions(+), 155 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2e42ed6..d0d5904 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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" diff --git a/src/jiangchang_desktop_wake/ACCEPTANCE.md b/src/jiangchang_desktop_wake/ACCEPTANCE.md index 63dee37..0149b6d 100644 --- a/src/jiangchang_desktop_wake/ACCEPTANCE.md +++ b/src/jiangchang_desktop_wake/ACCEPTANCE.md @@ -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` | +| 企微进程 | **不崩**、无「错误报告」对话框 | ### 失败时 diff --git a/src/jiangchang_desktop_wake/README.md b/src/jiangchang_desktop_wake/README.md index 13a49b8..ee8f910 100644 --- a/src/jiangchang_desktop_wake/README.md +++ b/src/jiangchang_desktop_wake/README.md @@ -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`。 diff --git a/src/jiangchang_desktop_wake/native/desktop-wake.exe b/src/jiangchang_desktop_wake/native/desktop-wake.exe index c3b800742be74401bbaa32af49c718bea2629b9f..81a4f6b34b793f64725c3f10850118f1d9cb2895 100644 GIT binary patch delta 37 tcmZpez}PT>aY6@^((H|0byfn8vMwn%%`5lnuJYb>BZF@0g#9SOOUaOemW5D>X-ZE`_({@Ip=UYEX^Ua7(3_;PoNR# diff --git a/src/jiangchang_desktop_wake/native/wecom_wake.dll b/src/jiangchang_desktop_wake/native/wecom_wake.dll index 2afe17a3a733248d87d2c7af912bdbe01591c888..63bc32025b58adba42bf513a3a5dbbf3b1ec4163 100644 GIT binary patch delta 25890 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 delta 26904 zcmeIadt6jiAOE`-7a0&_R6s<~QAb5Zo%{WQ35ta}C~{F$RMZhsNe3m<1_KHjDQs&) zX$E3NrAc9mhBk^R78R8lCKf$eZIhnJ%&2&r^I3ZawdXvq*YCW}Kj)vLukU`Z`&xUg z@A|H_*WN=>bwJU9fJy@q?lexbKlz{W<;{C%eAOp!#Uxy5f&ZLtgk-%-m_qhbpP2qW z%-(?vBd8}#^v;pP!jldYCcdvAN(*6{oHZ|yVbA&qRK*&UC`2eN+3)^j3?pKg?8zH) zmfDsw%=7|JPG%EmVog3#12lu-Y(usn@CduoXB;`jK8*-kJ;V4g%pkzkaMb4k@~mHY z@G5xS`F?H**S(4z=_d|W-wkllfaoyP@3x7K=?XTVq zkgQ^u;tTHLv(crl(4^DNt=qdK{TQYOEfdPmmY0a*;F~u;E#1*1PJq*@m`jA`6U1?D z`~zdX6#2(9Mes*cy2DE>L|E!72<4Nz!*}pr+YoCqa$DT?@G?(8KrYE8>Fzdel>p5! zW?d#ireI*PF`GJ2nuzvyNT?Zy-+z@;Es8?Q%PMsq|-?qJ~z8)Ds;ax!WAwrMGP(9sMej#ln;{ zR2fNc&214m62!vt1aX+7Uz*z@$YtE&IcUALKAaKe_M+G#6kBUWN$&7$M98l=T572G z1T&9slFij#yYt*vP&lGt&h9dNnB4|ub@91Av9U( zh0u~J>Lb=J#8wL~b8`b60*gDv9_hd!JGxWKZQ^K}UQl|waH1oGrYXH(8;QcgXkitp7q}&@Hqo2vP3M*mK$D?Gg;P*`7z!F!9+HY8QOw=;@x|FK zqPyh@QJ(m|0SLc4AQ%LX=l{VF$ggN)XjP%Ro8_Nr!|9F83*CK2enA^T?|yFR?$dIY z)}MB6O6YF8%Tf~uXBspo4x)fqEHw%QS>Q~XkBb$O4atJ!xWl(XO)cpaCE^koCaa5A zvzdQG%}T^O5Mr?&Nrk5U7=RwwA>M`YEXtT2*YeYORY+CtLLAc0@F%R z++!?Ibi4g&V^9w-v;{&g4w*1*#`lGS!Q64a+~6~j)Xv?P*d5F;2=tcjMPK>x-tzf5 ziOD|HZOigx&Nb3vEbj0sXdx;K>noM7Y?ik&A(WC%XN>2Nz65+5Q#={Z2pQ<6z&)lK zrJ!zhNMPJbk9o4C6dPlal_^NFRu7}*BCT90ruXVG8Z^!`zb$Sh^+2zJ)2u@1lZ9LP zCqIcJy_0wq-<)Xlt{;rrV)X0v{_JaklkMKBLesdvk)!ympWL+=ZL)S?Ks=-3%V!mM z!i{r_7^WbEnw-68u-x_E?Z4ZLX$~dT#dOD3aqxW#dWm;KIWIYsun=ro(1ytw&<<*i zm!N4z+P=`@R9ti2Rt5$iIzr92l}1>&2?q9d(8%G*$l~ZOz5|mULL(VmaQo4@Nb=ec zR@r}~z=9-c?(i&jaerNs7zL$qAqJ{h!5FLvi=|?^zlFQ;fG6aNEw0@6Mr^L1HI7gD zoxU$+SgG44q^bQZ+{p*n&i+YuYamt0Feq*_Iy4%Txt1)Z$~yaA3_9YjNf0^+tbpLW zKb=|BG&uNq1)aDXL+6<%CJC~}NK02SU0tnJh_kpaS=(qDex0c0myAorMmxXI z*3z}4zzR6FW1_KtQ~IT3AOjR=WD(_N=;j41kztPCBDrJuhl z_^Scw#BC7_okjteQMA376%vf7h%Rh~t=Of-G&Z9L~ z(wajIsIWF37j#%K=9(2n*6@B;L98_n={?$w4I5NKP;$lA&mDdQSsS5A%);Wc31|Em zblm|2p&3}X>3{S{smuP@l=+THRz##bj5(fo^wpP027KX3NtMx)`r9RoxZ7A#`Pvtw zzXswC%aHB7KWz`~o_n>+UEZqu=24#=%9)pz?lncTYv^Qm(8Xt~IMM-gghGXB>AA*v zDA{X`rlh6M9{DU{Y#YURO*FMQ( z(rc)XHc4oW}#2DyqJc5S zs=LY_j)8=-^E=-65>PU~;|)dcO{$?22998B8J;YlM|rs4Vq-k})xZ(GW`P=+m zqrb5T^CmnP9jAlwhZRY)rWDaaCeeA~4$sG(LXqS!>U5_}dnM9ZhYBs+;9vMo7txIb z`|_aC;dDt!GWwv7&?onzV5}vGxjINP>F&y5%W{O!okNNvgz9kLSn@-8kuO#83#%JE zMMBkwE+l~5bwgs!zT2N#Y+=x!jlQVi#t>_fCxU%`@G!EMeP{5vVDIW0k;dKrjpYW9 z>M#2p4+V6Ga^W{NJZyAG7VgPCCWF7GvgWXj{ko4}Cp3p`3>!P3x&!7RwDf(He%`;D z?Fth~JCM@aiVGJypJ6gH(I4YEA4~+yPm#5S#-63I=Td1b&1DRq8rXy&_a(P~9{Xgt zOd)&+36h}fHF^BN*|Fx|Sd~;uee&DW%L}d*ujpmCfzZ&h#Ln`9-eO}l`*ZjZQqB5D zEE}w$*eKJ29Uz`6G)`*ZidJVVIYfKKkDzoX;n1$=g9pPm>LbmdV$>8Ci%43Y>tJO5k zq-1#aKI2~mI1-s!8&AL5La-uHP+LO%r5(L^UiEjOhX}SBH8iqzD}3ku^KqpuKkskj zW9e8Gd0n}F8Eah3`Jxi`U}UUMcN%*sa`@Of+=e5uN1k}AJh9hfK%~?`4GbI=iCwt; z18mgLB_k@K0C>tlM6;E;x#|5etja5r<$uvJ5s2+J@M=oL{;O(gW>)B!diYUJv4 zPhbESgF(Cz$xVab!W~IRZlv{Xb`q0DDkm{ zyeA0x0+1u~#`Su#sJS0<78ze-rwogZ!}`fS0vVzC-zkE3YyFC8bxPSMPd)M zsFJOS8EQXEYiypEcB&JmNIySO2El1PR z%l|2@XQN`Rlrq8`w-Q~$V9O#b&l3wPAQL<1u@i^O!dht?io0TqLo(XXmAOHf&g{d( z50ExCV#I7*SBzLsTG=l~jK|eIVkNFCMG{<{q6Az!L{`$mCXP%ZvFy_$XOOmrOCu9W zm=cSjW4gdGJJ|OVd9VggjMqo8Q$|lD%h-jZTVs1*ei+*nD<#(+Ot2TC`_*9%B@Jgb)=A;JLXB!)bQ09J@M&QvO~tbOm?v+$88hrRxxyqXks6T9Unk@ z%=mH~yCGIGIqWJC+5#-xv$HXNi?C~~$;K@f_qc7MGz&Ks>l${YN*dL4+4>{e#swf@Ev+UKb@MaWN}FckUSju+A2B5m(ZwM&-VG&dPD_8!fLQr$9Hvx< z;!up+OB2wCBU`xJKb7qoKO#C6DX`5GtvMH&UePFq58J3D+W3%EcHD$-eSGz7(8TFc z^K^{RF)O&7z|dd+5Gqi-;w*DMv87ti=1xo@gl(GGIOr=RLQl{Ipx4{)PsHh?p83)3 z#!~Oz6z1N92SuzB?oD)2;Of{baiyf2T{>wR`I>!sQXYAj9W;3bbfs|eL}5_53Yo>vKp5$-k^+CDMr|@!HB?w|B6^{&Tpz9!RiFY#H;P9s!S|}5Sufs~buZ1ei(aTJ*OzZl zo_Gyf8R}@E({H?LR#YRuR}L<=hxrwx6`L4aO2rJE%&EBRY^7>c&^hb|Gczq|+(x!Z zl@Qtx@3Gg}v{dpV8>%*w3G5v8FfxE$qn=En*ca4F@-*9~9!?_IU)1Bs5O#=0Ob)UJ z&C(&}Zns;TFAOcIgQe%B@HsMs+<5kgCMlv56>0OMZOgbza5>_m%M)*LAF_kAZ<9j} z?`!)JvYl z<+E-@b1M?hTDWK|f!q>r5$T{~R&Vh(F*C0`Da?@=9GaLYws0xIvEVTtf|Uv9}C+1HSkPwQ|#0r|}GFVi%ZZ*t;=C zcmSiOtazy(<2YTsRKT2{>eqwt^MuCos^s_;XCmkOwZUI3Vv4i<7z<`nu?y!UQ?LSN zW_ru0nCf?)&{P&~3k|24y$KOz;dXrQcK^|y8Rg2n+h?GHpS* z!D*cDt^112HCSDA0Y1*AnMaM!#Vu!MmM6Ay3($*>c<4+EH-~qIl_#F%65uS)7jg!+ z#ypxtv+tWnM&IUWHz$sDs<%9Dg# z4C{)ICv#acHO#2KMr&-&^=o``2AYxhD+Z|nwu~Ry7=8!+EY+Bo5ayW0pC6PbMRQ4X zQ?rbnJ9R3V$?lpOH?oS}#LNyn7QpiHGl8QgOR&U_ZfwQ5UiRCmQ%C&^PcjIy`hwIB z%n-P3-F_T>opB??UC_lXU=tpgBw;zN=7HzQBdmU!x_>)HC^T`ZA5L=EN2e`=E_^-hCtNQiNJv-1UkQT=6lTD5D{(b! zo*v^%1nlmab4fu1H**?|iF+uYWV63MG@O0+p$Jh9bdEm6JHB5;Plg=1meExQqyI_{dzLM`s0x9(Ap81^S*Y?zBJU zmnc})@btos#OH~%4Ze%yKEvm)VT2@)5e|oBLv})(kmHauc@3#cmJ^=?Ga8O(Pw-1w zd)V#1;5nn>+d}oPr~hVA=+UAlHqxb|bOV6Z3mZJ23|#zf{Fy7b@jJE5p(B{(h|Gj6 zhOC0D*~ltZtoMmr-th8@WZz+e<*-qkCG*nG&Cn38AqHbI7#mQ*DI^G9J&>Rmhv$yN zu3~!bTq5!8wxFzw1q*KsqI1jru;0CHSf(Sfw|u(a^$?5^Hkt9q*p@XbV?@WGC70iV zD*ahxEWsLu=fdYPzG(9Ct?Wa2(F=+YsBf`Fq;PwXGt<#MZ{ECnw%l6%HTpHExQ7(< zw;qI>+e5dT=M#Hj!`+SmZDhefYd3Z^)=pfwWE>P^W?Fk_z%BN4-e6L~evvob=ffFn z%-XY~?|VjrGIF!1qQT(~@5Z>dVr>gAVg1%6`fxMYht`cTHlcrL;4Q?$kdL%pM1Z@X z8|x--o3L;|hwoe5innz$wm?2bCwpk!2vWp;v~D8V%Ko`-=D0H4sQmW4H12l|!<5Gq z{R{R7lO?7Sj?ybO{~|q8;QwwJyL$bSeq{)&Enz=iKO?9F&hkY)<>6%wBl3SDq>>HV zpb_jvSIFJ9l?@MWP!l`#(XHHZ+JlRl`&7lj=>4m_QTsemxlE&f5;|)8Da=c3|E-m@ zPwNqhF2y8daAdWM1~nqct)vBW%Xud)h|7QzjpimJyGJdr_q*fvcjpFMU97+DJT&Gb zTVB8@TE*=qHojm29Wf!gR9lTs}E4$&u3rtVYem;oyP&psL?c@V?@BuWKD?$La2Ia~f?8;550Ba7k zfm_bjZkiBz4J9!)fA027TGOItYhUE|n?%Dqsj~XK>UMJiJf%7EgE7FvX)p2m$d2Az zkE4W(n@`{_pDBD$NO!}n=T-DJ<47$j3YbQh(|8Zq|Z3HjH3rO4$ll&+@riF_leVq)$!=sD zw$1YqHL`-o*7}H+vzs3~Oc858J&fK8-M?42VF~TwOltbDThJe?a1QHN1e3?=il#)- zK}_R*!W_dE4>!&m`>**##YJPuS@!iJNk20k`}u5Vk<=dgR-cw|$rxGs_*{W=Gdw;w z@~M0gPrJ8rcI*+(-2&fqN2j9nJZbn}gh*=e9mQb|FELv56nm zN&hG-!opT=7s0l_wOtiO?YiSUC!@vj1@tvR!IH;S5!Vm*g>xrSzjb;ABi!G_&U!or zH`Vrd1pCh8QM@b8$M!Gw)5pWv!NpNtXUNitn9lv^BX+R0h)pSu45j__9@TcNgWK=4 zu!Y6bvHHAMJcJ}~d8W^x^J7d84s4U41TZtoThLv1crTiYn~m%{E#zLsO~Wj53$S@C zm!KX`57gXZN0pido=i*%ySj8ZX>BMgRS@9h6B-|~ioIR7k}&L|^4GE637#5Bh@73^ zI6@v{zj4eXPqFeHaWf9RicOp(6Fd7HpVMh&0W;=t6JDbac8;6+Z5;*uOK)!-XZJ7u zJ7|LlX@b(`agW~35!9EXr>^0Z9ZQIh@ZpAlrvrUQRpvwKrxQHYKhhSkSA# zIm|W9x7qi+TTxn>&&qZ_Lf&dPxO1Q{hUnC;Dm*5q@BRqaG0&|Z*@g}*pWhyu*i*i! z0~3E++w{`U9OtlO#QunDG%aj+=ec!c$fT`zCre67@ix4&oFANas=Yy1mEc1m}RpkQLIAKp*WgxnAG#Lk;4=x!>u;{`Ff#*#e| zq=${%W3Cv$ONS5ie{BPu(>UfrV%?CC@ULgy%Z z*kOAo4ijMM!~79B&N)6V?lhnNv)`IFjltcacy6yM%nzv??ex)oB9@+U z^W5Qr6t;8kWZY)xi=$vp`t3YJi11n1qS?3iUIYxV!Cl=yy6Bt}cc(hpA3~ zkNK88{o)W}WiP)NXJNkO4?_EH4ez3?P;8h|@8dX!_TGIQr%}bfL>B*>6x>)s-^cOO zVojnT(%)OoS$6)uJ@?eSXWw&Bm}g#k3)iXD@g%$9@#+P>M95yP{hNfbmk*5f$v(uA zmm^3p8~L&f*N0vnOTKB?@Uq$mSzdn?S=bw|7WMBzH)Ea+q`SIJb*qCOUPF}$JC{!O zdfhUT$0olvoaD1>URygv{4gD*8j%Ol9z;IO{_9dAgNx{{^!-EoW^JV<7Z`9p z3rFN<{FyCW@n29^9$cD>P}#kox!qQp!h(;A{=>ELZ%T0TM|0!kubErRCt&N}T#q+8 zqQiP3X0r}Ii36i+hrcAd*{1sLfw5>)E!~E=!{ewE2S;z6AriLe?b}4bZf=-KH0YaP8D+{6aHGhE$4-52SFx^f3`Q_vY$i<@gK-Mo!2 z@RhshmqA0Vw`i&^dbzcUUHs1Is4BF;A*V+eLHb`qODmD{Mii_?#>4EMcl1663)}wA zSm4>CqJJD=OguU~@|tHflkOd1==mcIcInZuq$*TG7utbm_=yjl{$D2#BL z?YOj4wAbiS0xoWwz^!tJccL$f$1?mxrOQJ>CnoB>WdkAJC4?>{?r;U)b+t4lEu03L z=*9c5cnpo92j`xE8tU~l0k3u)+XVV;!L}5~ACBR$Bm*2D(zA}w8>irYe2=Sf)gPaP z>+0hYRSz=uHKVU|5X+|MI5asm2cxs%8VoR}pwFmuHFv|ReR4b@8Xvm}xm(zXdJ|my z?!E+5PDJ|Ave~Q0#q9bM@jltd*|$!N@$vhPZ9lPG%zQ_yZ4`Lm=Rq&u7LTzBsb9`6 zd3R0}4XdT8YiXidPlnuBYy9zsmUoAd{zsM*VX$w&n()Tu?7y25a98q^^xl@9Tm>_8 z;iM=cm@nM(*y!L5IP@u)b)OtA^e7Ata_L4vfQ`bWQw~uzy{$P*@F0^Yz!#2^Z@hQq z;1`aX&W83=pZof>tzZwGiKY1R%w&py<`-cjUT#*Avke{1n|yI9H1GVAWD|Sk{8&tK zpB5#FY|ymS`jAf>IzHG#h>|UARg<6D`qp7M)NE}P!@T|4sv+`*2_LQX@$uWvKL3eA zDB2Fw6l{&8@V5%LvsXVE=_AR-1gd3xA?(?nrG}mv< z1&zb6w1;i@{sc*4*ZnZmhdIHP|Bx`8CM)08sZA7Y9idg6q{~`?l=~T*%yPezJ?xDi zqWLwo*cD&f!wP?l70?t|Ze48rkHeH+k9U=(2L$ud90h`Od;qsfujHG669mWCbn(5> zZ%q#x@nR2K`Qub9y`TL!$J59W|J_Ixx094Nv~ZGscw+tY-!0@__RKHOli%5_ZU?!= za^2f;&HZ(fPtvpO^S@5?Nq&|+_v`r3Sd5kD9G1?a6YQN|rKm=7b2t{cIXCm+cHIoe z_0r7;eX^3+QNK-tXXS5&xPJ4S9oHqd4&xg7`&p98Ui>`~*QndHrCGPfWM+BM()q>KQYdK5>-$;;F~cjE@>VTF5mFyStfd6o%ojX&-yIXAGZb z7~9>m1o|)sNP7&Qn*_P=2isv&Nrb zoBxs{@gIN9!F9&pB3!M1x8bVorIjz~-G=Mc-bebU@@BFikly{$|D=+hhNJ(9^BGx# zcd?0{;F)oi^*;eDcGL*ywzRCwTN@|@XipY0ok;z(5%66JNpLb`rtPIV( zvNAN|0~%I@u$#O;c2Xx_TITNvf4#fLxhIMY_o>{!`#Z8I&|AN7zjG!bBjb>%`NVZ> zV{gn^89FGOHs@yO;x@QL;^97l!xQEPK3*CWBH8bJj*yB8jRP6xYP9&b(8v75_$Hva z;(!=wn2J60imy6g(wNYa<@mUot#n5?-y2NA`-hgw;J+a%Hnuv8eaNUN6pgl_{johO zLpQdeg2!AdLsR|R_B-G6A;qzLGcpi=316aIO%VGvU-j=qVDrk*GchhW`XO~p_5NeI zzC`9rTAeTUBm05)0CIq|9{WCk48UWJ^Ok^&^2t8oj0_}GeR@Nj3j@iUB+wZYL`IWX z=j0$#I3U(DOn7S_iIH+12_h3nkMo-#GLb|(`}Zf~!terh48PdZKvmbUvyRgG5u@qABPHCdFK+ExVWtw9P5zNNDLA zPXRsqog)Vk|io7utW&72_A%r8CIs)K8 zao?gi(&QX6n2aL(ow~tfGJLBClW~FG(YDF@MtTl8s!QLR%I zMy8O1&Xr+gwDcgpJ;UPwbj6#h$eRl4HVon1BRJ7r(9FL&MaR`joF~G_DpKnl6;3vV z6`jBmXcu@^cF!_c>^vBbw)Hqa2`4E;>KqwC6hnB!It_;P5;d%U^;^>d!@9f2nHNDU ze)BqD=uy-jd6TZ{3HMD^rglTTtUs+xrBkS47R59tQ%(_&decXVZS%1HY7Mt3?aIS zv?R~AD2=`(^PY+0NTr=7YN0CAjUDAAs+A)mi8#s=L|-=04M8>Shjaeu2h6EOk>u1E z6n0wN_hhwTe zRMx-oKa9{)Ed~y`cmrhN-TyQ|*$C@1KrX%{j{$0XgBqX_82)#o$aKJG7#W}9sVdx4 zb?WJrp=oDshMs9-R))TRhAHl0YynsOV^QM$)`=$WvrZz!-DjPI2c27okvZfQC$=nS zP{}jVL;|>?$y8cp3{e5v7|c#&JXe~J<3!))pbG_uueM*AR75Mf?7IBzl}Y;!ItyY* zG7_JOA!X2K*KiW)Tt1wPht^jNCo)gaO8Ca%ycX%|Mv!L!jfjjGh;o8{w)tG{47y+w zT=nmF$Y~XkRC4ImlOjSMIz)t*FI@i5)yuT1ju->{7@K{KIBQ@wp6>|BLcoppuKFkZ zS3*T!LTUmw?du3hJ#m4^2j_aPxL-Ejk9h%*)d>{h6sHi zH`PS=liK;f1Tr>s@Z7#z$0s%Y<~lb|Ad@h9FHazbh!;}a?yHF+PtVY|Hx9q|^A0)x zm;eoZ&uN-SqQ;FzlEt0`R}*_^8V(;upfg9JGZDhS^x^(<%s!F4L*me2Mpwig(2e<6`DrRc8Ho5CH5k=|a(o&kj zYdTELF{hfC>C*b8hS=>vSMInQqmN=i+H>oUyRs6$B@t9S5bSucRo=q={1ue)!Ctt& zgR8NfCbRuB*)>F-yBnGQ&&XSde2qr-(ww?~Ms_1|#~K=&heP=5G5?J1MC^JRSw$n6 ze@4=*bMHoe_uD@jUW7;`B0UYCNR#o^Hyw-DVYWYKApZ9E2=gLgiZIMfzxN5#eU>mC zkdGl}Aa6tVL3ThQ5x)h@g=9cf>0qKJDKnA!7GaRCT zBtRBG?3-|T3bGe+5Yhtq0rD4Q01BP}Nq{Vd*dS$)I*1F>3b_VRp%G!2f(A$uBn^@S zSqIq)c^a}0QV%%=xd{0Qa{COiGd|6P83YkQ;vn%53uGB24^jvzfjkGPgPej~g!~&K zKo5jLMnNPH`cH>DjfMyy^xr=GEbVQ`ImjhQ7o_eK%7c`gT1S`-a4dtQK@uP`hzK$O z(u>5E5c=;Y_}d}pAoSnMas00kd3WFCqdG?T*BwUKJqlYE@4tv=8R4k0M7aAkylU+< zk_72`CXZRcEM=DC|70cyzC1qd)aA?Pt+354ShsHVx>fUStMgXd9+_ubYFptPX(G)| z&P3v3R;{otUA}zDh7~sBn0%4fw`O(DM&p>g9Oqy&8RJ{ry3gX}^SiRJ_%}g|Q>xLyu3vBC+lEN_(O<{cBdN$oJ$QlOy6i8`iH!C0@_c4IA#cmoKO8ob~Hg7^NY2=asv9>AF=; zt(gpdwZ}|+?AyNoP||jJLgE{Px4eHaY0SS5TuE~Ol1(0X{mE3J>6gsew9n{=r1S&R zeR9uWlr11a`k1i`3;_3f{dFL|2w{$ZsEToU*$QIE$aHw)IS^k%GTjUCLLt!k#WXU) zPSeLOB*Oln0;J`bK!Aw{>57{K()uhQRgYAV?n^Vg%<_h3d;K|HTD{BzX}b%({;eP_ zr)VLu^97Z7Bg(uHJG`v)au-Nf^eV4^ub0(c9sp^B>b(AgUVpvUf5hu=^!l5;bS<=d zT5{H#pvB8pFWbDl=w-W?9bR^Vv|-o0C>L^7=Ut zuko0$C7$#WPy~M}I12SMg>b|o-~c!QYy;`TO&3U&w->~NG`{HYC~2Q^M#E3TB_K_o z4ALIU25Ezez@cDY`aY%W(<#r8BW0g5?8O*St<<0^>5%NrKK4{1k@X99p`>1jW+@Rq zw}@z-OC}eC;_HcU-7H4^~QKChdq44<+XqVF@G*ekwr+ z8R0TW8^XFFsF9h4@ST;6@I2(PHyGj9kiXvZq<^c)lZK|F`6<_WnFi9ZA&|dNFWkr0 z&mpUcU9k%7h8Q66kOW8)BpG6XWI(bZR)`H!1Sx~;f>c5FLaHGLAa#&~kb1}wNF$^P z;)0xov_je;oe-LyTZQS}4Mz_IzeE-WL&6~VbXOP$kw6rXct|S5v-DsH;kH8ZA%&14 zNExIOQU$4lG(uV+9guDagHQLvAkh#pBo3ljjraEkI1(VqkW@$(BnOfQu|Y~8RgeP^ z1*9I*1Zjb^L%JZn5d6$oD2CuiK0*Z~36c*f$vviqy-XLfCfSuAp*SXpz0e9Dj@NYG6>_u1Kj9iomnI`)Sgu4v7#1`nuH9Hn*VH& znudIkE+2&;HC{y^ohW4>H4T*@T~4Y%x|~#lbOzUf^wYC?keZH0klG#>NY%In#7wp` zZE(;j+zt)~J3(p`IWQdT1|z^8kp8rRDfdiq0Z46;5TvFc5~L> zPz1($LKpjyX)^!G+|MhpV!j2H~wLOA`y6!zt1kAP!97dRGd1;>Hy;CS#FI03}l z1>r=n7mNc1JD?Mw2%G}Ofih47D!>Fg97;GWpbE?a)u0vBfHqJI7J)i&2dD?DKofWX zG=ueEJlF(I1zW&r;6*S2>;e1C? z1GIoS;9M{tOar%q>0lYS0IUL6fOX&+uo27yTfpt$MUV(E|2pCDgGHehFaYd=KM?Ez zgFwHhp*)}vq?RWd91O;SVW0wx0OP?ZFd2*ib3pocGV(z^SO%KFUEnmZ8eAiQx;Mf> zV6s|3Kky6t!_JF~l-!rHP6oPs%7F+`=K)Qua0R2D<7yxF0fuI!(0&QS0 zSOiAd;n)F(9;^ZhOkW-72Oa?fKo=MYwt_)mI~WXJ1EauhP!9?!ksl^95)1^zU=Sz) zgFyor1tx)dFdMWJ*vx!50>Q0d5LgCAfxAFGcn~BaC>IzAwtzw4MH&xw(s(f%LgT?+ z8V?F~A|4C_Nh}%!27(eW2sG@({3mf}5sd&-X#|)J5((xh4F?NpI9Ni%6_}C=%RiDdW`zPcIuBuk5NC^O__j(?u>;a2`zmVOh!v7Ets#M-&V|5FbXt0 zdu%qoIS#T@)A#^`8exOcP{#T^5k3qiVRZr+8~p8H5%?9j1AGgt0;|CT;4@%7_zBnq zegU?CpMe*_*T7EjIM@ZA1$)2_x?K9b;8_%eU@Ib`!S}#eumz;65M8Ad@b3YW!8M=- z;dI%{fqyymqrr6Rl@C99g4qgg1Ixf;UhVlZyX!z->RtdiV zjD^3Ju1*R#J_6&xgJ3dv0n7lO1#`d?U_SUhxD`ACmVuYRU0@qn4L$@O1YKYw_&HdG z3IoBj@P7)nfmgu}(EcSH92_5jx4?HmW-k$*27;zN6 zcfoA%V=xc=7Ayp>fFGyhwzzz_1swTpoo(gn%ZH z?j%fL9Q|>QQhom;gWBkNwIyz6A;Gavw zQO+c=1^x{*9)2l!5&l9j5;vp+JK=vEw6~*xfpE~hlNsznL^;?C&I8*~fD9DuBf>|( zeE7$JVeqd4t?-LM5&SE`IPht(8sQT`4g71t1h5#CpdKS=f&U3Q|3wJUBOnU_C149O zN93Ggt%`fIGnXAl+6E0;}ME4m<#+g7u&iq}%PmU=#cmU=PYwfi3Vq26iJp zjL!dy2uPy|5D*S_!k-RyfmJjd+yM$+BEpxzNU#oMP+$ZQ3x5VEfPV<6fIpLlz^(A-fMwt*unKGj>%e-j5o`oozz@N8 z@H{9&{wR=xKMOR#=6?s?g8vK{Tup>0K{055g(iUGc`z0khk>c^zW`=~i@;8V%fUSO zw}5ne9S;`5{}d>IUjvrGUjz!_*Mhs?-wsNUKN_rte=&FvTnB2(G5=%WXhgsgup0@L z;92;$g7is71h&Dy42(zoaIgdZY>p=R_4hXABKN?-Yp04;BNlrjSx34b<7r+F{psePa?!}7J<|rm4MXXE!zPHRpMPB?ee`K)vW^{o#qF@Nbm?qmA46`N_!Th zI@b!02HQY7tuKOfy0?R4!Ol0Gv!5q7125LY{>03+%Z z?i?95%9Y~TMj-3mzdcBAwB84%;%&T6sHT53a6(ik-h!v1Oq!1VBaj^U^Xi?C?IFV_ z-ycWgT}Z$8zVs-LIS7BFC(j4SW4}M1=IKQq?!G*JCJTZ-wlls(zC}525&RV=bS#(+eiFto z|ALHyI!GZ_sKI(jIP`T4q$3V$JBeYQfqV$L4S8}hG!XI(_F4pW&96yx!WH_&P@Ef~qYu#JVDKYYnxelVT)!Z)qY zv#q7Jp3Vt6H@szR*|H^P8Tw}e({aSxwhgxB;+a$VJI9|q@U)i?TfjH!nse$)XfOW4 zfv3GRD%BH(zrezDV+benjSypGFrU4D=yUQ4Ps8XR{G{#h4wj6jaUl#E+ZRSx0_GyZ z?i*AE4Wn=2jt21QoB`GN4nyReSxw|lEDMo7-;Z`qs3F4#ye7VP0K8Z1{J5G#^eY|1 z2oH>L{!~q(`mLFOL*oe^_Z_@33Rdv>reCsn@>PIN2>p2sC6IWU z$ouc9InJkR$fyYJ9T+=*79V`V0KiQ^!BOYA8Zx$@ERhka68ZW^egpS+5SrbDQ*z23 zM?H@bRp1flr2S-=&o{}=2ltbx$U#U#?M9*!Zxc~GEw&BGUdH6#2aPxTm+al%nTKJ#Je1la71tnjQDt zH$CBW*?YX|d? zH>7Wj=x+yUc%R?lOnI4%@R@&sFE)-w{n_d%q%X;l|H|_6NB332H){50yrTG&{>D?V z^7s2vjH6|CFdjSKS7z&fl{qkoI49PS7(v$%PeT5Vsm){3ohh%7VF73Hj<|Cyao(sV zLm#|u#)&nA#?yavkSNDuYS2M~P31*Erw>E~abXd!9DywwjIt8`X%Nf1&Qq@t(=v_s zB{nVN1YTh0z~mI&7j_3>2N4!~UsxL6pr;~?PRG7~Tj*PL*xYOPg}rc^FhUDmY9s#t zPa6Ke|D-|j|K^hh=U;WOAwzuUtyq`ijC+mzWq+EPwthZ7L|AQGy)8g_-L%+Lo?cj#TUOR>)U9sH8 z^keXm!-|a?S1-$3;R&LV>G-5z{btxn##7onTh6h>*GW1VaLqS){nDJ|)yp<4-S9~I zu@~MTY5vc>P3n9q*EnB)n>-sVT!;PBdYn*6=sa^mBeg!|(E?{UZOoFM&t z?Kzk^e@KK|NPsvJTlFvXSyc`GfL#@=W;}`4;(3`3v$>@@DxD@)(6yk*nCOs8zhF zIH5SFXj6Qra4SNTB4w7cNqJiNm0kI_aUQ-_^*GH+&00;J<}=MQ?FQ{u?GEj8+E=voT9@`S?G-Jj{aJfU z>(=(uMd*ggKmLtwQh&bsjJhysXMRxTz6UbweGs^-#Ysrx?bG?{Ybr5 zAFp4d->l!Jcjyo6kLcUS+(pHnLw_PPn9o|uaXzZOXbhXFUmXQp^Bl3af$~N3lt|6pD3PI zeyIFj8KoMnnygZ)l2mD`EY&iVmG9?ARgbIe<>+XqYM<(5)gje8s*|b~D^@Hk6^)mH(b*cJ2b&L8F^%v?Z>L1lv8b&M9rf5sFuWOHM+q9Ro9om0k z0RD{u2-FSNjnPfi8Fe#shjmT5PTg<1_w?=hf9ZSm{)Qk!j6rHp8D<)m+6|8x4jGOa zT!t0KBYc+*Gl@-;OmdUfG~2Ymlx0TyH*VK5PEKeAUcIuyaB0<9i`Vz2sf#G}&gT?oQc0nM)>< z*T}~!Rwy4<+MiPGRK2Tmscu5iBGo2!vU;w1t$MfmHTC_?ug;M;d{exh8k15=^N8E6KCo&b(^M}9p*|jtIE9B z%*5lt7L8$Ku`+{fw(JpEv8+~hNOs&V`$Be2c3t*wS)e>ZK0+>*kC!LNXUiAJm&kME zc6qscHzw0d@{{uO^3Ub%@~iSY@&SrS#VW-nMVhiieNwB|y=wTy5MT^3#u%p=A2IGT zuBA$6!NwXGAaO}2$s*-5<%<+66l*XAAJrCX%e7tFk-B)@CY?RNfK=HyF96P91XJ`+ z7@smeZG6`Fobd$|w%-_Fj-Umi`8Hs-e7<~xd=qB*WAex4zsaYn7pT{2c565-!IWF2 z+o*d?=g_@?X?9HaiSCl_U%J0^Ze4#pULs(AZP7~&8pDHzd4}f=uVTD7d5M`$N%=W7eKc5M`N_iY%81pRaR^Lk=PGrVuOV%TKV znx>lOnKqfqO}k95n2wu1GyQ2|%oEHSbBcMZ`6=^zP`yjEw<`G&!0}6fL@jwpG9QzC zujCa>^vjZeOL`3Qh@S+48>c@oU%!}7P}$K+qigO&3Q z+2$fzV6~_FL*%c>ZHfzuYYJawx$0vLr};zUuN|n3LDThGi*}XvDecSJw_y!G(SD`< zMeD2Uk70?^Ez{-dp3~LqzSl+TC+ipMx9h*x{|*ypk2TCUWEoZ&3JhBfj~iYz95BQi zryIXER${s_^`1&+!1%<<=fKRoApcXTgJFJG^}b4@-lIODzN(JZOwp(`Mol^lbG~L9 z`qHVnp}C_Ot$j%A)F0RXr4KWVMGXyxCXDzw!v}^o!$rf_hF=YCL%7|TXk2f6!zjm0 ze;V_<*UY$Zh>aU2=(=FZCz5kgp)5&emF?sl&GN1C?O0~^%U_irlz%F} zE+3&7i=}3^B44pZ@jRBB!;1G6-zt7n5M@7Qe`TyPS-DiXR=HXEgz{PCKILc1+pvib zz#iIDRV!6%RQa$1wW`Ca)3AP*VGD?Q6zsrL>PGc-wXbHlX1V4u+|_5A?=-hHZcU7K ztTs;T&_1hu9#-Ix_71vPpbJ4q%k>6*s{V0(y?&4((lFAXHOw%~Hl!QYqIU(xQO0q` z_2v_FINR_j1nja){+5ivqWiA&mb5>X*+a5+*-x@w*#NmnE`udVlUp&>cF6b1>v5mo z$$y8A4^`-~YNn{3RE@?m6a#xX5w;Sgb>iV0AgVx>PBm3^Nc#*{ycSHu2_~i+r?H6p zK^7n%ARi;wL(gW(7s~Dbmiu6#_!842PN`F-E0-wCl+P&NP`<6ap!^1%G*b1js#Mjg zYBi|MM)PrK_>XA6=R71#VwNOJ?2=uQeUeb=7-_!LE`3M(k#w?bsq9UepM0@=v|_d5 z4aFCV9!0S7X{Af~ld@OYPZg`0sXD6aQ2DCGcJ)gzv|Z}{n)A@)f!gU<&5vozU_RpX zub>Q;Y?aI=J0NS3eJ<;i-IDz&%Z5oFpxBLj6hpz* zK)rrb{;9m9^jC$$$S73Fs=2Dgs%@%b=+|D=LDl!F1?oKYW9mQEL=&hPs2OV4s5NFy zjpmT%wB{qtWzCw! z&%p%!O=pb6bKVv#iII$vC?(S+-$)#?-LltY4YCi>RJuVU^3n21*efK-x5+mtURVF1 zwrL7ATQ&9~=(JM1QD33or~d*KOg9`g5TnpI$@qZrVdHnEmDtN{Gw;D}<{hkJgkL8X zNvb8EOD-uRU;)mkzft$9hr$BP(`=#rkH;{m2h${NlU|gzORq^enC))WEme<-Q47>U ztg<3?EVgtSb-X&s`O-&Zrt_5+l4P&cR$(^PVJp`N^VNbKMZ2~W`-yICkCwsw66zv# zB3-ObqSIjMO43<$8MqpI)Se(3D-XrgoGYUV2 zKoP7ED#8@e3K15ISVf#dqEIL_ii8kFvLaQHp~zBXD{>Uhw=WQt-JptBCBRA~t1PNi zRR;D>*{U4up7LNYY^p+4iKp88`!d`UCP5nVzc7Qs+PwZR)M+67>%CF7;mZ0rf%k5p|RLth!ZwQQe`whIx4l zgX^aW)`V%IHDXPiMxili5;RPux3I;nD2xstK7y*o_y4Hp1H;FL&kUCgc}AOYtFgqm z!??@1*Lc8q5c|6(<5^>?@uIQAc+J>lyk+b)`k8`FVWw!xTBz2O5*x5Bo+9aKlYj#Zf9tk6jlnP+(6)^Y~ zWu7u$xkFj0tXDSTX`@})sl2AVh2>wYisOfq4q*|7kPhHp3|k`x>mr6p0o}|{XREE~ zo?Yr{Ja*ht_oyQ^8chZ!O_iom)2`{!L~1qI1r|bU8=? Kw #include #include -#include #include #include #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; diff --git a/src/jiangchang_desktop_wake/native_src/build.ps1 b/src/jiangchang_desktop_wake/native_src/build.ps1 index 80811db..c0dbbdd 100644 --- a/src/jiangchang_desktop_wake/native_src/build.ps1 +++ b/src/jiangchang_desktop_wake/native_src/build.ps1 @@ -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