From d38355ff164d14349a8675a88aa0c218c5a2b305 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Sun, 12 Apr 2026 09:16:54 -0700 Subject: [PATCH] Auto-map \\HOST to Z: from the W95TOOLS guest agent (#364) * Auto-map \\HOST to Z: from W95TOOLS at login W95TOOLS.EXE now calls WNetAddConnectionA("\\\\HOST\\HOST", NULL, "Z:") on a short retry timer (5 tries, 3s apart) so the shared folder shows up as a drive without a trip through Start -> Run. MPR.DLL is LoadLibrary'd so the EXE keeps its USER32/KERNEL32-only import table and still launches if MPR is somehow absent. Skipped if Z: is already taken; gives up silently if no share is configured. Works for any user folder because the SMB server's tree-connect already routes every share name other than TOOLS/IPC$ to the user share; added a comment in server.ts pointing at the dependency. Verified by cold-booting the image with the new vs. old binary in StartUp: new -> tree connect to \\HOST\\HOST within ~5s of desktop and z:\ opens in Explorer; old -> no SMB traffic after 55s at desktop. * Drop rebuilt W95TOOLS.EXE from the diff Binary will be rebuilt and baked into the image alongside the next default-state re-bake; keep this PR source-only. * Stop tracking guest-tools/agent/W95TOOLS.EXE It's a build output of `make -C guest-tools/agent` and CI doesn't consume it (the disk image is baked out-of-band), so there's no reason to carry the binary in git. --- .gitignore | 1 + guest-tools/README.md | 12 +++++---- guest-tools/agent/W95TOOLS.EXE | Bin 22528 -> 0 bytes guest-tools/agent/w95tools.c | 47 ++++++++++++++++++++++++++++++--- src/renderer/smb/server.ts | 3 ++- 5 files changed, 54 insertions(+), 9 deletions(-) delete mode 100644 guest-tools/agent/W95TOOLS.EXE diff --git a/.gitignore b/.gitignore index 5d77128..4a5d826 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,6 @@ trusted-signing-metadata.json .env electron-windows-sign.log .npmrc +guest-tools/agent/W95TOOLS.EXE /.claude/scheduled_tasks.lock /.claude/worktrees/ diff --git a/guest-tools/README.md b/guest-tools/README.md index ed69af1..2c56486 100644 --- a/guest-tools/README.md +++ b/guest-tools/README.md @@ -25,11 +25,13 @@ Install inside the guest: ## agent/ — W95TOOLS guest agent `W95TOOLS.EXE` is a hidden-window agent that talks to the emulator over -the VMware backdoor (port 0x5658). Currently it does one thing: bridges -Windows 95's `CF_TEXT` clipboard to the host (legacy backdoor commands -6–9; host side is `src/renderer/clipboard.ts`, which polls Electron's -clipboard). It's also where time sync, host-initiated shutdown, and a -tray icon will live when those land. +the VMware backdoor (port 0x5658). Currently it bridges Windows 95's +`CF_TEXT` clipboard to the host (legacy backdoor commands 6–9; host side +is `src/renderer/clipboard.ts`, which polls Electron's clipboard) and +auto-maps `\\HOST\HOST` to `Z:` at login via `WNetAddConnection`, so the +shared folder shows up as a drive without a trip through Start → Run. +It's also where time sync, host-initiated shutdown, and a tray icon will +live when those land. Install inside the guest: diff --git a/guest-tools/agent/W95TOOLS.EXE b/guest-tools/agent/W95TOOLS.EXE deleted file mode 100644 index d8903de0c1c6ea78b30674c563466d4b714f2926..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22528 zcmeHvdt98w)&H~0E-VRTNx~{>q8q!Zp(b&kg#?z}g#`iun+vyGj2eRh0+9eN&*oxN z-MF9(k84wFTkET@rqNby-_}~SNW5?{KvLThjA=ApFh={}CKZh)ghcoEJ@f1mh`oK@ z-~0Kzf4qH?nVmT^bLPyMGiT1+Sh~h1Xaqsf!G%JC(1u_7+}!`io)5`Wu4tbkJRAFm zS#6pnf0$KPUDIgB|8n!Hn!1YmEsf@7W#%nBSXp7N+*-NbE0y0|TNyve5=LE=CkRV4 zI$>|@k(x+tgTkGf$r|l6VG$scRA~Qn{3gJyqqtiQYX#6gnE;%A9(eS81j+cQ5L##s z2haZ?gm0Z79MSX8-}ZJ2!rR20|KTrtMcHyfd1nqhB9Yp9K|N+rH@~K$Tq+OKxDI)u z;R@i!eQrVMShTog`HCVzSb8xM8sG@mGPrS{8~NsYDr@W4hkrNQRec6QVBH%vA=ANfx6s_-y;wZ*0$@U0_3EW7+gGm?gcC!1 z5ibpy26+x+)ANW@iPsQkc_Ymo#-@h>Dhin-4mn2V5P=B+8Aqm-mU2zG{klX^0oGn#&{$fpI;QM?Ho)XSkyRJROet) zZ1)SXsBs+C{vKWM=OOP%$g~wSgiLMl_uaI1&2`szkF~rAjipgGt{CfW?%4ikPVnt2 z!GXn^qH3)fO4C$Jt;s|Cr02$3JED>gOfeT=>SCR8-iT(nB_Xg@V}EaRbmzy0mLiSX zpg6X_^Wy}hx0FR|)%I{uk_w9A)!9J94jFVR+$V-!Uj82D&^ju-QizH#kXnd3)7@Kb8VFSX_f}uwd z@sDbaOZY$kq2N2A1q1;4r;(r6 zbC?2X;W4W3C5{fs9f)ycrF~GV)w%}CMA_yd0rgG|nU)~r`W?tMHg&;AN6|zxuFH3v zC0Um)-D#^gBEU!<_i(`4O5xk$}9b|cj zS>D^dd4ohlAn!%ARRIFf;*BGc&i_+uQArJ%UQ`MFk(wUJJBEV&9CrIfYU~_hYUovj zf``NoPS6kyv8V*Mu)LwN&b+EzT3^4(oO?~~)mNw3%q8Bsd1W=5D$R}C8l}oj^Ub;S z4ck058>%Jqob}1(2}SDbBu~xFUa8*GXtr6cws|(IZQ*=#QN2g1sjq7sUo_hB*nZ_21Oj;@%8xOb$?*?S$<8R>`{$H=%-Hr$k0^GiU`^ldN0F*51AOD8 zUE2{ZBG!dWtHGQi<#Pz#Pzn-@m45iUI4U9nBn$@kfUd~rPZzwJ?odK^z(=5+q!n6v zUVhYrUT=ZNK5hBT-n02qU%FPB+`3hhKI+l2&X!SsN3@GFc|O{4hJL+zu2cfqTIETM zwjPZ(_)1`rStu=D+0xx|=;db!A!P)@wc5kmTv5;JbqH0lXaFJUbO*5IdW zp|~QX^Iy=*x}mXkq|(HJUUwYHs$xQ`L#9Pw2J`9_MrmgOx;vCUt!WQmaPsjSSa+g#(RuiI2vCzV1%>NYfH3yUkIuY>dmP)TFMT zK8J)(C828f?+_3>s&>)uj-xcS?0$iRI!6tUQZ4{d*Y1}%u%*An^gKelJK^mjm~5gT z%`yGE_afwTQ6Zht{~$`Wx61T$-|{vJdrDP(dYm+}}*!CkFMyA8#@`BT1U(MHu29qS~s*;m-$Dy(+KWdu=9?Du}Gg8o`1!}BXjivd!w80aBB5jr9 zQps55&k&?ofDpLS`zeq1Q;y&B;9d$o)9&F6YeC)3A#W^K2RE&~u3P1i+3yxsj%Sgj z3G5y2)i)tOB`T*dANT5aB1%bP#UUS%_f;!)5tAVFbL4nxLGwPz$oj-1%6r7bnFR8? zs7nN|>BgJXfuVF$nu!Vq_f^jWdAw7<-kq^BFS;r;Af90J2#bnB6=LWI2xt%cvl5jE z)e{y6*3Cx64#f?v)BXTTs6wvngg~%iCHW#q(kx>9BWKZJrfTG9BcW8jhd9`BePj@n zT`90mkBM^ukArmDBk1C&=ga}M&;nh?i z;etZlf=~hlt&+#O*x=P#cKpUQ0FQm$-K-N+56VVJm>VWRN@ypd+Y;cZ)vEbmG$J?a z8_EXV=d&nUP!W8abxp|CKXe�YmrQI!jTJyvSlGa=h9&^XgYmA6`j@0Z_@qs~yp6 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 L^8fz+DF^-^X{mz= diff --git a/guest-tools/agent/w95tools.c b/guest-tools/agent/w95tools.c index 29edaad..7195671 100644 --- a/guest-tools/agent/w95tools.c +++ b/guest-tools/agent/w95tools.c @@ -1,7 +1,8 @@ /* * W95TOOLS — guest-side integration agent for the windows95 emulator. * - * Currently: bidirectional text clipboard. Talks to the emulator over the + * Currently: bidirectional text clipboard, and auto-mapping the host's + * SMB share to Z: at login. Talks to the emulator over the * legacy VMware backdoor (port 0x5658; implemented in v86's vmware.js). * Joins the Win32 clipboard-viewer chain so guest copies are pushed * immediately, and polls the backdoor on a timer so host copies show up @@ -29,6 +30,17 @@ #define POLL_MS 250 #define MAX_CLIP 0xFFFF +#define TIMER_CLIP 1 +#define TIMER_MAP 2 +#define MAP_TRIES 5 +#define MAP_DELAY 3000 + +/* The host SMB server routes any share name other than TOOLS/IPC$ to the + * user's folder, so a fixed UNC works regardless of which directory they + * picked. */ +#define MAP_DRIVE "Z:" +#define MAP_UNC "\\\\HOST\\HOST" + extern unsigned long bd(unsigned long cmd, unsigned long arg); #pragma aux bd = \ "mov eax, 564D5868h" \ @@ -49,6 +61,27 @@ extern unsigned long bd_ebx(unsigned long cmd, unsigned long arg); static HWND g_next; static int g_ignore; +static int g_map_tries; + +/* Map \\HOST to Z:. Loaded lazily so we don't grow a link-time dep on MPR; + * if the call fails (no share configured, network not up yet) the caller + * retries a few times on a timer and then gives up silently. */ +static int map_host_drive(void) +{ + typedef DWORD (APIENTRY *WNetAddConn)(LPCSTR, LPCSTR, LPCSTR); + static WNetAddConn fn; + DWORD rc; + + if (!fn) { + HMODULE mpr = LoadLibrary("MPR.DLL"); + if (!mpr) return 1; + fn = (WNetAddConn)GetProcAddress(mpr, "WNetAddConnectionA"); + if (!fn) return 1; + } + if (GetDriveType(MAP_DRIVE "\\") > 1) return 1; /* letter taken */ + rc = fn(MAP_UNC, 0, MAP_DRIVE); + return rc == NO_ERROR; +} static void push_to_host(HWND hwnd) { @@ -114,7 +147,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) switch (msg) { case WM_CREATE: g_next = SetClipboardViewer(hwnd); - SetTimer(hwnd, 1, POLL_MS, 0); + SetTimer(hwnd, TIMER_CLIP, POLL_MS, 0); + SetTimer(hwnd, TIMER_MAP, 1, 0); return 0; case WM_DRAWCLIPBOARD: @@ -129,12 +163,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) return 0; case WM_TIMER: + if (wp == TIMER_MAP) { + if (map_host_drive() || ++g_map_tries >= MAP_TRIES) + KillTimer(hwnd, TIMER_MAP); + else + SetTimer(hwnd, TIMER_MAP, MAP_DELAY, 0); + return 0; + } pull_from_host(hwnd); return 0; case WM_DESTROY: ChangeClipboardChain(hwnd, g_next); - KillTimer(hwnd, 1); + KillTimer(hwnd, TIMER_CLIP); PostQuitMessage(0); return 0; } diff --git a/src/renderer/smb/server.ts b/src/renderer/smb/server.ts index 281d44c..c70e629 100644 --- a/src/renderer/smb/server.ts +++ b/src/renderer/smb/server.ts @@ -373,7 +373,8 @@ export class SmbSession { // Path is \\SERVER\SHARE — route by the share segment. Unknown names fall // through to the user share so a stale `net use` (e.g. from before the - // user re-pointed the mounted folder) still connects to *something*. + // user re-pointed the mounted folder) still connects to *something*, and + // so W95TOOLS.EXE can hard-code \\HOST\HOST when it auto-maps Z:. const share = reqPath.split(/[\\\/]/).pop()?.toUpperCase() ?? ""; const isIpc = share === "IPC$"; this.tid = isIpc ? TID_IPC : share === TOOLS_SHARE ? TID_TOOLS : TID_SHARE;