mirror of
https://github.com/felixrieseberg/windows95.git
synced 2026-05-09 00:24:09 +00:00
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.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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/
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user