# probegen

> **Tool `tools/pe/probegen.py`** (program, Windows PE). Write a probe library: a stand-in for a DLL a game imports, which logs every call it gets.

Run it with `./gameframe run probegen ARGS` or `python3 tools/pe/probegen.py`. [Source on GitHub](https://github.com/tanepiper/game-frame/blob/main/tools/pe/probegen.py).

## Its own help

This is the help text in the tool itself, as `./gameframe tool probegen` prints it.

```text
Write a probe library: a stand-in for a DLL a game imports, which logs every call it gets.

Usage: probegen.py GAME.EXE DLL OUT_DIR [--words N] [--stdcall NAME=BYTES ...] [--log FILE]

  GAME.EXE   the 32-bit Windows program (or DLL) that imports DLL
  DLL        the library to stand in for, as the import table names it (glide2x.dll, S3DTKW.DLL)
  OUT_DIR    where to write NAME.c, NAME.def and build.sh
  --words N  for an import whose argument size is unknown, log N stack words (default 4)
  --stdcall NAME=BYTES   the import NAME is __stdcall and takes BYTES of arguments (the callee
             removes them). Decorated names (_grDrawTriangle@12) say this already; undecorated
             ones (S3DTK_InitLib) need it, or the game's stack goes wrong after the call
  --log FILE the log file the probe writes, in the game's folder (default probe-NAME.log)

Then `sh OUT_DIR/build.sh` builds NAME.dll with `zig cc -target x86-windows-gnu`. Put it beside
the game in place of the real library and run the game (in Wine or a VM). Each call appends one
line to the log: the import's name, then each argument word in hex. A pointer argument shows
as an address. Every stub returns 0.

Why: before a replacement library can draw anything, you need to know which calls the game
makes, in which order, and with what arguments. A probe answers that from the running game,
with no SDK and no headers. POD settled the layouts of two card APIs this way
(docs/hardware/replacement-libraries.md, "Start with a probe").

The exports are exactly the import table's names, through the .def file, so decorated
stdcall names such as `_grGlideInit@0` match. Imports by ordinal are exported at the same
ordinal. The probe uses only kernel32 (CreateFileA, WriteFile, CloseHandle): no C runtime.
It does not read through pointers, return useful values, or keep a game running past the
first call whose result it checks. Standard library and pefile.
```
