mw4print: document known issues and research notes

Captures all findings from the 2026-08-07 debugging session:
print flow diagram, DoPrint error codes, which commits changed what,
hypotheses explored/ruled out, and next steps once the -debug log
is available.

Co-authored-by: Claude Sonnet 4.6 (Anthropic) <noreply@anthropic.com>
Co-authored-by: GitHub Copilot <copilot@github.com>
This commit is contained in:
2026-08-07 21:55:35 -05:00
co-authored by Claude Sonnet 4.6 GitHub Copilot
parent 3256c103a2
commit 77e19a723c
+168
View File
@@ -0,0 +1,168 @@
# mw4print ? Known Issues & Research (2026-08-07)
## Symptom
Printing is broken in the current build (post-`b98cb87e`).
- **Without MySQL enabled:** never prints, neither on mission-end (WM_COPYDATA) nor on manual File ¡æ Open.
- **With MySQL enabled:** app locks up ~5 seconds, prints one mission, then never prints again until restart.
"Anymore" = it worked before the MySQL/banner commits.
---
## Print Flow (how it works)
```
Game (MW4.exe)
¦¦¦¡ SendMessage(WM_COPYDATA, filename)
¦¦¦¡ CMainFrame::OnCopyData
¦¦¦¡ CChildView::DoCopyData ¡ç adds CMyPrintInfo to m_lstMPIs queue
1-second WM_TIMER
¦¦¦¡ CChildView::OnTimer
¦¦¦¡ g_RSF.LoadPR(p->m_strFile) ¡ç opens and parses .pr file
¦¦¦¡ g_RSF.DoPrint() ¡ç if nErr==0: remove from queue
¦¦¦¡ g_RSF.Reset()
```
Manual path (File ¡æ Open) also adds to `m_lstMPIs`; the timer handles both cases identically.
### DoPrint() internal flow
```
DoPrint()
LoadPrintParams() ¡ç reads options.ini / banner.txt
count m_pScoreObjects ¡æ nPlayers
if nPlayers == 0: return 0 silently (no print, item still removed!)
PrintDlg(PD_RETURNDEFAULT | PD_RETURNDC)
¦§¦¡ fail ¡æ nErr = -1, CommDlgExtendedError() has the reason
¦¦¦¡ ok ¡æ hDC set
MakeInfoTable / params.LoadParameters
[#ifdef MW4PRINT] if g_dbConfig.bEnabled: DB_ExportMatch() ¡ç 5s timeout here
SetupFonts(DPI) fail ¡æ nErr = -2
StartDoc fail ¡æ nErr = -3
per-player loop:
StartPage / DoPrint(hDC, ...) / EndPage fail ¡æ nErr = -4
EndDoc (or AbortDoc on error)
DeleteDC / delete pInfoTable
return nErr
```
### Key return codes
| nErr | Meaning |
|------|---------|
| 0 | Success (or nPlayers==0 ? silent non-print) |
| -1 | `PrintDlg` returned FALSE ? check `CommDlgExtendedError()` |
| -2 | `SetupFonts` failed |
| -3 | `StartDoc` failed |
| -4 | `EndPage` failed mid-print |
---
## Commits that changed mw4print
| Hash | Description |
|------|-------------|
| `b98cb87e` | **MySQL export, configurable banner text** ? first change |
| `9f3a5044` / `a45be804` | Version bump to 2.0 (rc only) |
| `515adc24` | **persist banner text via banner.txt** ? second change |
| `3256c103` | **-debug diagnostic logging** (current) |
### What `b98cb87e` actually changed inside DoPrint
The ONLY addition inside DoPrint when MySQL is disabled:
```cpp
#ifdef MW4PRINT
if (g_dbConfig.bEnabled) {
DB_ExportMatch(...); // ¡ç gated; skipped when bEnabled=false
}
#endif
```
So with MySQL disabled, `DoPrint()` is byte-for-byte identical to the pre-`b98cb87e` code. If it's failing, the failure is NOT in this block.
### What `515adc24` changed in LoadPrintParams
Fixed a missing backslash in the `options.ini` path:
```cpp
// before: strOI += "options.ini"; ¡æ "C:\MW4options.ini" (wrong)
strOI += "\\options.ini"; ¡æ "C:\MW4\options.ini" (correct)
```
Side-effect: before the fix, all layout params used their hardcoded defaults. After the fix, they read from the real `options.ini`. If that file has unusual values, print layout could differ ? but all params are clamped to sane min/max so they can't cause a crash.
---
## Key facts established
- `MW4PRINT` IS defined ? it's in `mw4dummy.h` (`#define MW4PRINT`), which is `#include`d before everything in `ChildView.cpp`.
- `DB_ExportMatch` is called **after** `PrintDlg`, not before. The 5-second "lockup" with MySQL = connection-timeout inside `DB_ExportMatch`, which is reached only after `PrintDlg` has already succeeded.
- `LoadPR` always returns `true` if the file opens, even if the meta-header parse fails. If parse fails, `m_pScoreObjects = NULL` ¡æ `nPlayers = 0` ¡æ `DoPrint` returns 0 silently.
- `AssetsDirectory1` has no trailing backslash (stripped in `InitInstance`).
---
## Hypotheses explored (and ruled out)
| Hypothesis | Status |
|-----------|--------|
| MySQL blocks before PrintDlg | ? Wrong ? DB_ExportMatch is called *after* PrintDlg |
| MW4PRINT not defined | ? Defined in mw4dummy.h |
| options.ini path fix breaks layout | ? All params clamped; can't cause crash |
| Message-map corruption from new dialogs | ? Maps look correct |
| LoadPR always fails | ? Returns true if file exists, regardless of parse |
| Memory corruption from DB code | Unconfirmed |
| PrintDlg returns FALSE (no default printer) | **Active hypothesis** |
| nPlayers == 0 (parse failure / all bots) | **Active hypothesis** |
---
## Current debugging approach
Commit `3256c103` adds a `-debug` flag. Run:
```
mw4print.exe -debug
```
Output goes to `mw4print-debug.txt` next to the exe (append, timestamped).
### What the log tells us
```
DoPrint: nPlayers=0
```
¡æ File opened but no players found. Either the .pr file has an unrecognised meta header,
or all players are bots and `g_bPRTest=false` (no "Include Bot" checkbox ticked).
```
DoPrint: PrintDlg FAILED nErr=-1, CommDlgExtendedError=0000100A
```
¡æ `CDERR_NODEFAULTPRN` ? no default printer is configured on this machine.
```
DoPrint: PrintDlg FAILED nErr=-1, CommDlgExtendedError=00000000
```
¡æ PrintDlg returned FALSE with no error. Unusual; may indicate a hidden dialog or
modal conflict.
```
OnTimer: LoadPR FAILED for 'C:\...'
```
¡æ `fopen` failed ? file was deleted between WM_COPYDATA arriving and the timer firing.
---
## Next steps
1. Build from current source on Windows (quick ? only `ChildView.cpp` recompiles).
2. Run `mw4print.exe -debug`, do File ¡æ Open on a known .pr file, wait 2 seconds.
3. Read `mw4print-debug.txt` and look for the first failure line.
4. Act on the specific error:
- `nPlayers=0` ¡æ check .pr file validity; check if "Include Bot" is needed
- `CommDlgExtendedError=0000100A` ¡æ configure a default printer on the test machine
- Other ¡æ investigate that specific failure path