diff --git a/mw4print-issues.md b/mw4print-issues.md new file mode 100644 index 00000000..4aa8ae1f --- /dev/null +++ b/mw4print-issues.md @@ -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