Dear Randal,
On SET FILEHANDLES
You're right โ there is no SET FILEHANDLES command in xHarbour, and my earlier reference to it was incorrect. There is no runtime SET that controls the number of open file handles in xHarbour. Historically in Clipper/[x]Harbour the open-file limit came from SET FILES in CONFIG.SYS and the C runtime's max-open-files, not a language-level SET.
The "amount of files handles available" text you may have seen is just a hard-coded error message string inside _EndPage(), shown only when the temp file can't be found after closing the metafile โ it is not tied to any settable option. 1-cite-0
What the code actually does per page
In _StartPage(), for each page a temp filename is generated and a new enhanced-metafile DC is created: 1-cite-1
In _EndPage(), that DC is closed and deleted, so the GDI/file handle for each page is released as the page ends โ which matches your Task Manager observation that GDI objects don't grow. 1-cite-2
Note that ::aMeta grows by one entry per page and the .emf files are never deleted mid-job โ a 1000+ page report leaves 1000+ temp files on disk until End(). That's a scaling concern but not by itself the silent-crash cause. 1-cite-3
The temp-filename generator is a real weak point
cTempFile() builds the name purely from GetTickCount() and only loops until the name differs from the immediately previous name or an existing file: 1-cite-4
For fast, high-volume printing this is fragile:
- GetTickCount() has 10โ16 ms resolution, so a tight page loop can spin here, and the uniqueness guard (cOldName + File()) is weak. 1-cite-5
- If a collision or timing edge produces a path that CreateEnhMetaFileW can't open, the C wrapper returns without calling hb_retnl/hb_retnll, so ::hDCOut becomes NIL instead of a valid handle โ and the next GDI/close call operates on a bad handle. This is a plausible route to a silent native crash and to a 0-byte last file. 1-cite-6
This also fits your "can't even print one page" reports: a single failed CreateEnhMetaFileW on those machines (permissions/AV locking the temp folder, temp path issues) yields NIL ::hDCOut and the same failure pattern.
Honest limits of this analysis
I could read printer.prg, metafi32.c, and filename.prg, but I cannot diff against the pre-25.09 version from the index, so I can't point to the exact line that changed in 25.09. The intermittency + silent GPF is still most consistent with either (a) ::hDCOut becoming NIL on an intermittent CreateEnhMetaFileW failure, or (b) heap/handle behavior in the native layer. 1-cite-7
Recommended next steps
- Report to FiveTech with your stress-test repro (silent GPF at CreateEnhMetaFile, regressed in 25.09, 0-byte last EMF). This is library-level.
- Instrument the failure: right after the CreateEnhMetaFile call in _StartPage(), log ::hDCOut and Empty(::hDCOut). If it's NIL/0 on the failing page, that confirms the CreateEnhMetaFileW return path is the trigger. 1-cite-8
- Test with a stronger temp-name scheme to rule out cTempFile() collisions.
I can prepare a concrete patch if you want. Two independent, safe changes are possible:
- Harden cTempFile() to use a counter/hb_randStr-style unique component instead of only GetTickCount().
- Fix CREATEENHMETAFILE so it always returns a value (e.g. return 0 on failure) so the PRG can detect the failure instead of receiving NIL, plus optionally suppress the modal MessageBoxW.
Both require recompiling FWH sources (the .prg and/or the C file). Tell me whether you can rebuild the FWH libraries (including the C sources in source/winapi/), and which change(s) you want, and I'll produce the exact patch.