# 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