Issue: Lessons learned connecting FiveTechSoft Harbour + HMG rddads to OpenADS server
Summary
Successfully connected a FiveTechSoft Harbour 3.2 + HMG 3.4.4 (32-bit, MinGW) client to OpenADS 1.8.83 remote server. Documenting issues encountered and fixes applied to help other users.
Environment
- Server: OpenADS 1.8.83-1-gd89f323 (
openads_serverd.exe x64)
- Client: FiveTechSoft Harbour 3.2.0dev (r2410251209) + HMG 3.4.4.ssl3 (built from source)
- ACE DLL:
ace32.dll built from OpenADS source via CMake (msvc-x86-static preset with /MT)
- Import library: Generated with
dlltool --no-leading-underscore from openace32.dll
Issues encountered and fixes
1. Import library: ordinal vs name-based exports
Problem: The OpenADS openace32.dll exports both ordinal ([41] AdsConnect) and decorated name (_AdsConnect@8) exports. The initial import library was generated using ordinal matching, which worked for x64 but caused crashes on i686 (32-bit).
Fix: Generate the import library using name-based exports with --no-leading-underscore:
dlltool -d ace32.def -l libace32.a --no-leading-underscore
This ensures PE import names (_AdsConnect@8) match exactly what the DLL exports, avoiding ordinal mismatches.
2. Missing VC++ runtime (static CRT fix)
Problem: The MSVC-built ace32.dll required VCRUNTIME140.dll. On machines without the VC++ redistributable installed, the client crashed silently.
Fix: Rebuilt ace32.dll with static CRT using the msvc-x86-static CMake preset (/MT flags). The resulting DLL only depends on KERNEL32.dll and WS2_32.dll.
3. URI must include the data directory path
Problem: Using tcp://127.0.0.1:16262/ (empty path) in AdsConnect60() caused "Connect: path outside data directory" error.
Root cause: In session.cpp, resolve_under_root() returns std::nullopt for empty client paths (path.cpp:105). The server requires a non-empty path to resolve against its --data roots.
Fix: Include the data directory in the URI:
tcp://127.0.0.1:16262/D:/path/to/data
This matches the pattern used in unit tests (tests/unit/) and the E2E test (tests/e2e/README.md).
4. CDX index file must exist before remote USE
Problem: USE CCOLONIA.DBF ALIAS CCOL NEW EXCLUSIVE VIA "ADSCDX" hung indefinitely (never returned) when the .cdx file did not exist.
Root cause: Server error 5103 (OpenIndex: CCOLONIA.cdx) — the ADSCDX RDD automatically tries to open a matching CDX file. If it doesn't exist, the server returns an error but the client-side RDD doesn't handle it properly and hangs.
Fix: Create the CDX index file locally before connecting remotely:
USE CCOLONIA ALIAS CCOL NEW EXCLUSIVE VIA "DBFCDX"
INDEX ON CCOL->COLONIA TAG COLONIA
INDEX ON CCOL->NOMBRE TAG NOMBRE
CCOL->(DbCloseArea())
5. ? console output in GUI mode
Problem: Using ? (console output) inside functions called from a -gui build caused HMG ErrorSys to catch an error and show a "Program Error" dialog, even though the ? calls were harmless.
Fix: Replace all ? console output with file-based tracing (MemoWrit) for GUI applications. Use append-on-write pattern:
FUNCTION _tlog( cFile, cMsg )
LOCAL cOld := ""
IF File( cFile )
cOld := MemoRead( cFile )
ENDIF
MemoWrit( cFile, cOld + Time() + " " + cMsg + Chr(13)+Chr(10) )
RETURN
6. DBF file must be valid before remote open
Problem: The initial CCOLONIA.DBF was created with incorrect parameters (empty field descriptors, RecSize=0). The server would accept the USE but the client would hang.
Fix: Ensure the DBF has proper structure with valid field definitions before connecting remotely.
Key patterns from unit tests
The OpenADS unit tests (tests/unit/) reveal the correct API usage patterns:
| Aspect |
Pattern |
| Local connect |
AdsConnect60(dir_path, ADS_LOCAL_SERVER, nullptr, nullptr, 0, &hConn) |
| Remote connect |
AdsConnect60("tcp://127.0.0.1:<port>/<data-path>", ADS_REMOTE_SERVER, ...) |
| Open table |
AdsOpenTable(hConn, "filename.dbf", ...) — bare filename only |
| Data path |
Goes in the connection URI, not in the table name |
Suggested improvements
- Better error reporting for ADS 5103: When a CDX file is missing, the client-side RDD should return an error instead of hanging.
- Empty URI path handling: Consider defaulting to the server's
--data root when the client sends an empty path in the URI (with a deprecation warning).
- ACE DLL version string: The built-in
AdsVersion() returns "1.8a" which is the DLL header version, not the server version. Consider including the OpenADS git version.
Files modified
colonias.prg — Main program with file-based tracing
colonias_common.prg — Remote connection flow with verbose trace logging
- Import library:
libace32.a generated with dlltool --no-leading-underscore
Issue: Lessons learned connecting FiveTechSoft Harbour + HMG rddads to OpenADS server
Summary
Successfully connected a FiveTechSoft Harbour 3.2 + HMG 3.4.4 (32-bit, MinGW) client to OpenADS 1.8.83 remote server. Documenting issues encountered and fixes applied to help other users.
Environment
openads_serverd.exex64)ace32.dllbuilt from OpenADS source via CMake (msvc-x86-staticpreset with/MT)dlltool --no-leading-underscorefromopenace32.dllIssues encountered and fixes
1. Import library: ordinal vs name-based exports
Problem: The OpenADS
openace32.dllexports both ordinal ([41] AdsConnect) and decorated name (_AdsConnect@8) exports. The initial import library was generated using ordinal matching, which worked for x64 but caused crashes on i686 (32-bit).Fix: Generate the import library using name-based exports with
--no-leading-underscore:This ensures PE import names (
_AdsConnect@8) match exactly what the DLL exports, avoiding ordinal mismatches.2. Missing VC++ runtime (static CRT fix)
Problem: The MSVC-built ace32.dll required
VCRUNTIME140.dll. On machines without the VC++ redistributable installed, the client crashed silently.Fix: Rebuilt ace32.dll with static CRT using the
msvc-x86-staticCMake preset (/MTflags). The resulting DLL only depends onKERNEL32.dllandWS2_32.dll.3. URI must include the data directory path
Problem: Using
tcp://127.0.0.1:16262/(empty path) inAdsConnect60()caused "Connect: path outside data directory" error.Root cause: In
session.cpp,resolve_under_root()returnsstd::nulloptfor empty client paths (path.cpp:105). The server requires a non-empty path to resolve against its--dataroots.Fix: Include the data directory in the URI:
This matches the pattern used in unit tests (
tests/unit/) and the E2E test (tests/e2e/README.md).4. CDX index file must exist before remote USE
Problem:
USE CCOLONIA.DBF ALIAS CCOL NEW EXCLUSIVE VIA "ADSCDX"hung indefinitely (never returned) when the.cdxfile did not exist.Root cause: Server error 5103 (
OpenIndex: CCOLONIA.cdx) — the ADSCDX RDD automatically tries to open a matching CDX file. If it doesn't exist, the server returns an error but the client-side RDD doesn't handle it properly and hangs.Fix: Create the CDX index file locally before connecting remotely:
5.
?console output in GUI modeProblem: Using
?(console output) inside functions called from a-guibuild caused HMG ErrorSys to catch an error and show a "Program Error" dialog, even though the?calls were harmless.Fix: Replace all
?console output with file-based tracing (MemoWrit) for GUI applications. Use append-on-write pattern:6. DBF file must be valid before remote open
Problem: The initial
CCOLONIA.DBFwas created with incorrect parameters (empty field descriptors,RecSize=0). The server would accept theUSEbut the client would hang.Fix: Ensure the DBF has proper structure with valid field definitions before connecting remotely.
Key patterns from unit tests
The OpenADS unit tests (
tests/unit/) reveal the correct API usage patterns:AdsConnect60(dir_path, ADS_LOCAL_SERVER, nullptr, nullptr, 0, &hConn)AdsConnect60("tcp://127.0.0.1:<port>/<data-path>", ADS_REMOTE_SERVER, ...)AdsOpenTable(hConn, "filename.dbf", ...)— bare filename onlySuggested improvements
--dataroot when the client sends an empty path in the URI (with a deprecation warning).AdsVersion()returns "1.8a" which is the DLL header version, not the server version. Consider including the OpenADS git version.Files modified
colonias.prg— Main program with file-based tracingcolonias_common.prg— Remote connection flow with verbose trace logginglibace32.agenerated withdlltool --no-leading-underscore