Blog › ICP guides

WinDev developer on retainer: HLock record lock not released, PC SOFT WinDev, HyperFileSQL HFSQL developer on monthly retainer

October 8, 2026 · ~15 min read

A WinDev developer was maintaining a stock management application built in WinDev 27 for a regional wholesale hardware distributor. The application managed warehouse inventory and included a “Receive Stock” procedure that allowed warehouse staff to record incoming shipments and update bin stock levels. The procedure was implemented as a WinDev window procedure named pUpdateStockLevel that operated on the STOCK table using HFSQL Classic — PC SOFT’s proprietary local file-based database engine that stores data in .fic files on a shared network drive. The procedure called HLock(STOCK, StockRef, hLockWrite) to acquire an exclusive write lock on the current stock record before reading the existing quantity and performing the update. It then applied a warehouse-capacity validation: if the sum of the existing quantity plus the quantity received exceeded the bin’s maximum capacity, the shipment could not be accepted for that SKU. The developer tested the validation against a batch of test SKUs where all received quantities fit within bin capacity. In production, three SKUs arrived with quantities that exceeded their respective bin capacities, triggering the capacity validation failure. The failure branch called HCancelBuffer(STOCK) to discard the pending field changes and then returned from the procedure without calling HUnlock. HCancelBuffer cancels all pending modifications to the in-memory HFSQL record buffer — it resets the buffer to the last-read values — but it does not release the explicit file-system lock acquired by HLock. Three STOCK records remained exclusively locked on the shared HFSQL Classic data files for the remainder of the warehouse workstation session. Other WinDev workstations accessing the same shared STOCK table received “Record locked” error messages when attempting to read or update those three SKUs. Concurrent blocked workstations: 3 → 0 after adding HUnlock(STOCK, StockRef) on the failure branch before returning.

The root cause was a misunderstanding of the distinction between HCancelBuffer and HUnlock in WinDev’s HFSQL API. These two functions operate on completely separate aspects of the HFSQL record model and cannot substitute for each other. HCancelBuffer (W-Language: HCancelBuffer(FileName)) cancels all pending modifications to the current record in the HFSQL in-memory buffer: any field assignments made after the most recent HRead, HSeek, or HLock call are discarded, and the buffer is reset to the values read from the file. This function affects the in-memory state of the buffer only; it has no effect on the HFSQL file-system lock that was acquired by HLock. HUnlock (W-Language: HUnlock(FileName, KeyValue) or HUnlock(FileName)) releases the explicit write lock acquired by a prior HLock call on the specified file and key value. It does not modify the in-memory buffer — the field values currently in the buffer remain accessible after HUnlock is called. To properly handle a validation failure after HLock, both operations may be needed: HCancelBuffer to discard the in-memory changes, and HUnlock to release the file-system lock. A developer who calls only HCancelBuffer intends to “undo the edit” but leaves the lock acquired; a developer who calls only HUnlock releases the lock but leaves any in-progress buffer modifications intact (which may be harmless if no further HModify is called, but is poor practice).

The HFSQL Classic multi-user locking model is implemented using file-system locks on the shared .fic data files rather than a centralized lock manager. When a WinDev application calls HLock(STOCK, StockRef, hLockWrite), HFSQL Classic calculates the byte offset of the StockRef record in the STOCK.fic file and acquires an exclusive operating-system file-system lock on that byte range from the Windows process running on the workstation. Because the lock is managed by the Windows file-system lock mechanism on the shared network drive (typically a Windows file server or NAS), it is owned by the specific WinDev process on the specific workstation. The lock persists until the WinDev application calls HUnlock to release it, or until the WinDev process terminates (which causes the OS to release all file-system locks held by that process). Other WinDev workstations that attempt to call HLock (or to read the same record in certain lock modes) on the same STOCK.fic file at the same byte offset will receive an HFSQL error “Record locked” (“Enregistrement verrouillé” in French-language WinDev documentation). In HFSQL Classic, there is no lock timeout mechanism: the calling workstation either acquires the lock immediately or receives the “Record locked” error immediately. There is no waiting; the application must handle the lock error and retry if desired.

HFSQL Client/Server mode changes the lock architecture but not the HLock/HUnlock programming model. In HFSQL Client/Server mode (available from WinDev 14 and increasingly common for applications that outgrow shared-file HFSQL Classic), the HFSQL server process (hfsserver.exe) runs on a dedicated server and manages all record access for client applications. WinDev client applications connect to the HFSQL server using a network protocol rather than directly accessing the .fic files. When a WinDev client calls HLock, the HFSQL client library sends a lock request to the HFSQL server; the server grants or denies the lock and tracks the lock in its lock table. An HFSQL Client/Server lock persists on the server until the client calls HUnlock or the client’s connection is dropped. Unlike HFSQL Classic’s immediate-error behavior, HFSQL Client/Server can be configured with a lock wait timeout (via HSetLockWaitDelay) so that lock requests wait for a specified period before returning a “Record locked” error. The HLock/HUnlock programming model is identical in both modes — the same bug (HLock without HUnlock on the failure branch) produces the same symptom (other workstations receive “Record locked”) in both HFSQL Classic and HFSQL Client/Server deployments.

WinDev, the W-Language event model, and the HFSQL record-locking API

PC SOFT is a French software company that has developed the WinDev Integrated Development Environment since 1993. WinDev is a RAD (Rapid Application Development) environment for building Windows desktop applications using W-Language, PC SOFT’s proprietary 4GL. The WinDev product family extends to WebDev (for building server-side web applications deployed through the WebDev Application Server) and WinDev Mobile (for building iOS and Android mobile applications). All three products share the same W-Language syntax and the HFSQL database engine, allowing developers to share significant amounts of application logic between desktop, web, and mobile targets from a single WinDev Studio IDE project. WinDev is particularly widely used in France and French-speaking markets, though it has a global user base especially in manufacturing, logistics, retail, and professional services.

WinDev’s HFSQL (formerly HyperFileSQL) database engine is the default data storage technology for WinDev applications and comes in two configurations. HFSQL Classic (formerly HyperFile) is a local file-based engine: data is stored in .fic files (data), .ndx files (index B-trees), and .mmo files (memo data for large text and blob fields). Multi-user HFSQL Classic access uses OS file-system locks on the shared .fic file. HFSQL Client/Server is a centralized engine where the HFSQL server process manages data files, indexes, and row-level locks on behalf of all clients. Both modes expose the same HFSQL function API to W-Language code: HReadFirst / HReadNext / HReadLast / HReadPrev for sequential navigation; HSeek / HSeekFirst / HSeekLast for indexed search; HAdd / HModify / HDelete for write operations; HLock / HUnlock for explicit record locking; HCancelBuffer for discarding in-memory buffer changes; and HTransaction / HTransactionCommit / HTransactionRollback for transaction management. WinDev also supports external databases (SQL Server, Oracle, MySQL, PostgreSQL, DB2) via HFSQL HF SQL (OLE DB or ODBC connector mode), where the locking semantics are governed by the external database rather than HFSQL.

The W-Language event model organizes all WinDev window logic into event procedures that respond to UI and system events. A WinDev window has initialization events (Initialization, WindowInit), button-click events (ButtonClick or the button’s dedicated code block), field-change events for edit controls (ExitFromField, FieldModification), and close events (Close, WindowClose). WinDev procedures called from event handlers are written in W-Language and can call any HFSQL API function directly. A procedure like pUpdateStockLevel called from a button’s click event runs synchronously in the same WinDev process thread; any HLock calls within the procedure acquire OS file-system locks that persist for the life of the WinDev process unless explicitly released with HUnlock. A window’s close event does not automatically call HUnlock on any locks acquired by procedures called during the window’s lifecycle. Only process termination or an explicit HUnlock call releases an HFSQL Classic file-system lock.

WinDev version history affects the specifics of the HFSQL API and locking behavior. WinDev versions prior to WinDev 24 used a slightly different HFSQL function naming convention in some cases, and HFSQL Classic file format versions changed between WinDev 18 and WinDev 24 (requiring HConvertFile or HChangeDir operations when migrating data files). In WinDev 27 and 28, PC SOFT introduced updated HFSQL Client/Server capabilities including improved lock wait timeout configuration and enhanced HFSQL monitoring tools in the WinDev Studio IDE (the HFSQL Control Center shows active connections, active locks, and lock wait chains for HFSQL Client/Server databases). Applications originally developed in WinDev 18 or 22 and migrated to WinDev 27 may encounter changed behavior in certain HFSQL automatic replication or synchronization features, but the core HLock/HUnlock semantics have remained consistent across all WinDev versions. A retainer developer migrating a WinDev 18 application to WinDev 27 should audit all HLock calls to confirm that HUnlock is present on every non-HModify exit path.

Typical WinDev developer retainer work and what it looks like in a work log

HLock without HUnlock on business-rule failure branches is the canonical WinDev invisible production lock. The pattern is consistent: a W-Language procedure acquires an explicit write lock with HLock(FileName, KeyValue, hLockWrite), reads the current record values, applies a business-rule validation (capacity check, availability check, credit-limit check), and on the failure branch calls HCancelBuffer to discard the in-memory field changes before returning — but omits HUnlock. The developer tests with data where all cases pass the validation; the HLock-without-HUnlock path is only exercised in production when a real boundary condition is encountered. Three stock records locked for the workstation session; other WinDev workstations on the same shared HFSQL Classic data drive receive “Record locked” errors for those SKUs. Fix: HUnlock(STOCK, StockRef) added on the failure branch before the RETURN statement. Concurrent blocked workstations: 3 → 0. Work log: “pUpdateStockLevel: HLock(STOCK, StockRef, hLockWrite); capacity validation failed (quantity + received > BinCapacity); HCancelBuffer(STOCK) + RETURN without HUnlock; 3 STOCK records locked (file-system lock on STOCK.fic) for WS session duration; other WS workstations received ‘Record locked’ on those 3 SKUs; fix: HUnlock(STOCK, StockRef) added before RETURN on failure branch; blocked workstations: 3 → 0; 1.5h.”

HFSQL Classic index corruption after abnormal workstation termination is the second most common WinDev retainer pattern. HFSQL Classic’s .ndx index files are not journal-protected against mid-write corruption by default (journaling is a separate optional feature introduced in later WinDev versions). If a WinDev workstation terminates abnormally (power failure, forced kill, operating-system crash) while an HAdd or HModify operation is in progress writing to both the .fic data file and the .ndx index B-tree, the index may be left in a partially-written state. Subsequent HSeek or HReadFirst operations using that index return wrong records or skip valid records. The fix is to call HRebuildIndex(FileName) (from a maintenance utility or a WinDev repair procedure) to rebuild all .ndx index files for the affected table from the .fic data file. HRebuildIndex requires exclusive access to the .fic file — all other workstations must close the file before HRebuildIndex can run. Work log: “STOCK.ndx index corruption after WS power failure; HSeek(STOCK, hStockRef, StockRef) returning wrong record for known-existing StockRef; verified via direct .fic scan with HFSQL Control Center; HRebuildIndex(STOCK) from maintenance utility (exclusive access; all other sessions closed); 3 wrong lookups → 0 after rebuild; 1.5h.”

HFSQL transaction lock accumulation from HTransaction without HTransactionRollback on error path is the third common WinDev retainer pattern in HFSQL Client/Server deployments. A W-Language batch procedure that wraps a set of HFSQL write operations in an explicit HTransaction / HTransactionCommit block must call HTransactionRollback on every error exit path. HTransaction begins an explicit transaction on the HFSQL Client/Server connection; all HAdd, HModify, and HDelete operations within the transaction scope acquire row-level locks on the HFSQL server. If the procedure encounters an HFSQL error (detected via HError() returning non-zero) and returns without calling HTransactionRollback, the transaction remains open on the HFSQL server connection, and all row-level locks from HAdd / HModify operations performed so far are held by the server until the client connection is closed. In a multi-user HFSQL Client/Server environment, accumulated transaction locks from an error path block concurrent workstations from accessing any of the locked rows. Work log: “pBatchStockReconciliation: HTransaction(STOCK); 50-record loop; on record 22, HModify(STOCK) failed (HFSQL error 54: duplicate key conflict); IF HError() <> 0 THEN RETURN END without HTransactionRollback; 21 STOCK row locks held on HFSQL server for WS session; 21 concurrent workstation accesses blocked; fix: HTransactionRollback(STOCK) added in error handler before RETURN; HTransactionCommit confirmed on normal-completion path; 2h.”

Track WinDev developer retainer hours without the status emails

When a 1.5-hour investigation traces 3 concurrent “Record locked” errors on warehouse workstations to a missing HUnlock call on the bin-capacity validation failure branch — WinDev’s HFSQL Classic file-system lock acquired by HLock is not released by HCancelBuffer; only an explicit HUnlock call releases it — the work log must name the procedure, the HLock call, the capacity validation that failed, the exit path that omitted HUnlock, the lock duration, and the blocked workstation count before and after. HourTab gives your WinDev retainer client a public dashboard URL they can bookmark: hours used, hours remaining, and a work log naming the HFSQL locking fix. No client login. No status emails. CSV in, URL out.

See HourTab pricing →

How HourTab tracks WinDev developer retainer hours

WinDev HFSQL HLock-without-HUnlock bugs are invisible by the same mechanism that makes them hard to diagnose: HLock succeeds with no error; the capacity validation correctly detects the violation; HCancelBuffer cancels the in-memory changes with no error; the RETURN from the procedure exits normally with no error; the WinDev application shows the user a validation message and returns to the input form. No WinDev error dialog appears. No HFSQL error is logged. The warehouse workstation session continues normally; the operator moves on to the next SKU. The only evidence of the problem is on a different workstation: a warehouse operator attempts to look up one of the three locked SKUs and WinDev displays “Record locked” (“Enregistrement verrouillé”). Connecting the “Record locked” error on workstation B to the missing HUnlock on workstation A requires either using the HFSQL Control Center (WinDev’s database management tool, included with WinDev Studio) to query the active lock table on the HFSQL Classic shared file (for Client/Server) or correlating the locked byte offsets in the .fic file to the record keys held by workstation A’s process (for Classic), or reviewing the pUpdateStockLevel W-Language procedure source code to find every HLock call and every exit path that does not call HUnlock.

The work log must name the mechanism to be auditable: which W-Language procedure (pUpdateStockLevel), the HLock call (HLock(STOCK, StockRef, hLockWrite)), the business-rule validation that failed (quantity + received > BinCapacity), the exit path that omitted HUnlock (HCancelBuffer(STOCK) + RETURN without HUnlock), the records locked (3 STOCK records by file-system lock on STOCK.fic), the concurrent blocked workstations before and after fix (3 → 0), the fix (HUnlock(STOCK, StockRef) added on failure branch before RETURN), and the verification (tested capacity-exceeded scenario from two WinDev workstations simultaneously; second workstation no longer receives “Record locked” after first workstation hits the capacity validation failure and returns). A log entry that says “fixed record lock issue in stock update, 1.5h” is not auditable. A log entry that names pUpdateStockLevel, the HLock(STOCK, StockRef) call, the BinCapacity failure branch, the 3 locked STOCK.fic records, and the HUnlock-before-RETURN fix is auditable and defensible to the wholesale hardware distributor client. HourTab gives WinDev developers a public retainer-hours URL they send to clients — wholesale distributors, manufacturers, retail chains, and professional-services firms that built WinDev applications in the 2000s and 2010s for stock management, order processing, billing, and field service dispatch, maintained today by the original WinDev developer or a successor retainer consultant.

Comparative context: WinDev HFSQL HLock-without-HUnlock lock-hold bugs are structurally identical to explicit-lock-acquire-before-business-logic patterns in other RAD environments where the developer explicitly acquires the lock before the validation check. Advantage Database retainers cover the Delphi TAdsTable.Edit-without-Cancel pattern where ADS acquires a server-side exclusive lock when the Delphi TDataSet enters dsEdit state, and the lock is not released if the event handler calls Exit without calling AdsTable.Cancel. Paradox retainers cover the LOCKRECORD-without-UNLOCKRECORD pattern in ObjectPAL where Paradox acquires a process-level lock that is not released by table.close() on the failure branch. Magic xpa retainers cover the contrasting implicit-transaction lock pattern where Magic xpa’s platform acquires the database row lock automatically when the task enters Modify mode, and the lock is not released when Quit task is called without a Rollback transaction operation.

FAQ: WinDev developer retainers

What does a WinDev developer on retainer typically do?

A WinDev developer on monthly retainer covers HLock / HUnlock record lock-hold audits (reviewing every HLock call to confirm that HUnlock is called on every failure exit path before the procedure returns); HCancelBuffer vs HUnlock distinction debugging; WinDev application migration from WinDev 18/22 to WinDev 27/28 (W-Language API changes, HFSQL file format migration); HFSQL Classic performance tuning and index maintenance (HOptimizeIndex, HRebuildIndex after abnormal termination); HFSQL Classic to HFSQL Client/Server migration planning; WebDev server-side session management for HFSQL Client/Server connections; and WinDev Mobile HFSQL data synchronization debugging (bi-directional sync between WinDev Mobile .fic files and HFSQL Client/Server).

What WinDev HLock record lock work is most commonly underlogged?

Stock management and inventory adjustment procedures that call HLock to acquire an exclusive write lock, apply a capacity or availability validation, and on the failure branch call HCancelBuffer to discard the field changes without also calling HUnlock to release the lock are the most systematically underlogged WinDev retainer work. HCancelBuffer cancels pending HFSQL record buffer changes — it has no effect on the file-system lock acquired by HLock. The developer who calls HCancelBuffer on the failure branch intends to cancel the edit, but the lock remains held. Three stock records locked for the workstation session; other workstations on the same shared HFSQL Classic data directory receive “Record locked” until the original session closes or explicitly calls HUnlock.

What are typical WinDev developer retainer rates?

Entry-level WinDev developers with experience in basic W-Language window and procedure development, HFSQL table navigation, and standard event handling typically bill at $55 to $95 per hour. Mid-level WinDev programmers with experience in HFSQL record-locking (HLock, HUnlock, HCancelBuffer, HModify), HFSQL Classic to HFSQL Client/Server migration, and WebDev session management typically bill at $80 to $150 per hour. Senior WinDev developers with deep knowledge of HFSQL locking semantics, WinDev version migration expertise (WinDev 18 to 28), HFSQL index integrity management, and production incident forensics on legacy WinDev 15–22 applications typically bill at $120 to $210 per hour. Monthly retainer ranges: $1,400 to $2,500 per month for advisory engagements covering lock audits and version migration reviews (12 to 18 hours per month); $1,800 to $3,800 per month for active maintenance including lock audits, version migration, and HFSQL index maintenance.

What should a WinDev developer retainer agreement include?

A WinDev developer retainer agreement should specify: WinDev version (WinDev 18, 22, 24, 27, 28); HFSQL mode (HFSQL Classic with shared .fic files, or HFSQL Client/Server with centralized server process); whether the retainer covers WebDev or WinDev Mobile components; whether HFSQL index maintenance (HRebuildIndex after power failure or abnormal termination) is in scope; whether the retainer developer has access to the WinDev Studio IDE with the .wdp project file for recompilation and deployment; whether HFSQL to SQL Server / Oracle / MySQL migration work is in scope; and whether the retainer covers HFSQL Client/Server monitoring via the HFSQL Control Center (active connections, lock wait chains, and performance dashboards).

How should WinDev developer retainer hours be logged?

Log each WinDev retainer session with the procedure name, the HFSQL locking operation, and the lock state outcome. For HLock without HUnlock on failure branch: procedure name (pUpdateStockLevel), the HLock call (HLock(STOCK, StockRef, hLockWrite)), the business-rule validation that failed (quantity + received > BinCapacity), the exit path that omitted HUnlock (HCancelBuffer + RETURN), records locked (3 STOCK records via file-system lock on STOCK.fic), concurrent blocked workstations before and after fix (3 → 0), fix (HUnlock(STOCK, StockRef) added on failure branch before RETURN), hours (1.5h). For HFSQL Classic index corruption: table affected, HRebuildIndex call, wrong-result count before and after, exclusive-access requirement, hours. For HFSQL Client/Server transaction lock accumulation: HTransaction / HTransactionCommit / HTransactionRollback scope, rows locked, fix (HTransactionRollback in error handler), hours.