ByRef parameters are extra outputs
ByRef NewPremium As Currency, ByRef Warnings As Variant returns two values besides the function result. A REST response must carry all three, and callers that ignored one of them should be identified, not assumed.
Migration guide
VB6 ActiveX DLLs often sit under several applications at once, behind ProgIDs nobody has listed. This guide shows how to extract each component's contract and its consumers before you replace it with a REST service.
By Pranav Kulkarni, Head of Language Engineering · Updated 15 Oct 2026
Technical syntax challenges
ByRef NewPremium As Currency, ByRef Warnings As Variant returns two values besides the function result. A REST response must carry all three, and callers that ignored one of them should be identified, not assumed.
MTSTransactionMode = 2 (RequiresTransaction) enlists the component in a distributed transaction, and SetComplete or SetAbort votes on its outcome. Database writes made by the component, and by components it calls, commit or roll back together. REST services need an explicit replacement, such as a single local transaction, an outbox or a saga.
Err.Raise vbObjectError + 1001 defines an error contract callers test by number. Each code becomes a documented HTTP status with a problem details body, and the spec lists which callers branch on which codes.
Parameters typed Variant may carry strings, numbers, arrays or Empty depending on the caller. Arrays cross COM as SAFEARRAYs with their own lower bounds. Type inference across all known callers is needed to define the JSON schema.
Components are created by ProgID (CreateObject("PolicyLib.clsPolicySvc")) from VB6 apps, classic ASP pages, Office macros and scripts. Only some of those are in source control. A caller inventory is part of the contract.
Extraction workflow
The sequence a PYD ENTERPRISES Discovery Scan runs for this stack. Every output links back to source file and line range.
Provide the ActiveX projects (.vbp, .cls, .bas), compiled type libraries, COM+ catalog exports and the source of every client application you have.
PYD ENTERPRISES builds each class's public interface from source and type library, including ByRef outputs, optional parameters, default members and instancing settings.
MTSTransactionMode, ObjectContext votes and every Err.Raise path are recorded per method, so transaction scope and error codes are part of the spec.
Early-bound references and CreateObject calls with literal ProgIDs are linked to the component methods they call; callers outside ingested source are listed as gaps to close.
Calculations and validations are sliced out of each method and exported as DMN tables, separate from COM and database plumbing.
Each public method becomes a candidate REST operation with request and response schemas, error mappings and fixtures that can be run against both the component and the new service.
Legacy in, specification out
Left: the VB6 COM / ActiveX construct as it sits in production. Right: the reviewed artifact your REST services engineers build against. PYD ENTERPRISES produces the spec and the tests; your team writes the service.
LEGACY SOURCE
1' PolicyLib.dll, MTSTransactionMode = 2 (RequiresTransaction)2Public Function Endorse(ByVal PolicyNo As String, _3 ByVal EffDate As Date, _4 ByRef NewPremium As Currency, _5 ByRef Warnings As Variant) As Long6 Dim ctx As ObjectContext7 Set ctx = GetObjectContext()8 On Error GoTo Fail9 If EffDate < Date Then10 Err.Raise vbObjectError + 1001, "PolicySvc", "Backdated endorsement"11 End If12 NewPremium = RatePolicy(PolicyNo, EffDate)13 Warnings = Array()14 If NewPremium > 25000 Then Warnings = Array("UW_REVIEW")15 ctx.SetComplete16 Endorse = 017 Exit Function18Fail:19 ctx.SetAbort20 Err.Raise Err.Number, Err.Source, Err.Description21End Function
EXTRACTED ARTIFACT
1paths:2 /policies/{policyNo}/endorsements:3 post:4 operationId: createEndorsement5 x-pyd-source: clsPolicySvc.cls:2-216 x-pyd-transaction: COM+ RequiresTransaction (SetComplete / SetAbort)7 x-pyd-callers: [PolicyAdmin.vbp frmEndorse, Underwriting.vbp modBatch]8 requestBody:9 content:10 application/json:11 schema:12 type: object13 required: [effectiveDate]14 properties:15 effectiveDate: { type: string, format: date }16 responses:17 "201":18 content:19 application/json:20 schema:21 properties:22 newPremium: { type: string, description: "Currency, 4 dp" }23 warnings:24 type: array25 items: { enum: [UW_REVIEW] }26 "422":27 description: vbObjectError + 1001, backdated endorsement
Architectural best practices
In depth
VB6 shops built ActiveX DLLs to share logic between desktop apps, web pages and batch scripts. Two decades later, those components are effectively internal platforms with unknown consumers. Replacing one with a REST service is safe only if you know its full contract, including ByRef outputs, error numbers and transaction behavior, and every caller that depends on it.
PYD ENTERPRISES extracts the contract, the rules inside each method and the callers it can see in ingested source, and lists what it cannot see as gaps for your team to close (for example from COM+ usage logs or desktop inventory). It does not generate the REST service or a COM proxy; your engineers build those against the reviewed spec.
The method has one rule (no backdated endorsements), one derived warning (premium over 25,000 triggers underwriting review) and a call to RatePolicy whose own rules are extracted separately. The transaction behavior matters: because the component requires a COM+ transaction, any database writes inside RatePolicy roll back when SetAbort runs. The REST design must keep that all-or-nothing behavior or document why it no longer applies. The comparison EffDate < Date also uses the server's local date, so the spec records the time zone the component ran in.
FAQ
From a compiled DLL, PYD ENTERPRISES reads the type library for interfaces, parameters and types. Rule extraction requires VB6 source; without it, methods are listed with their signatures and flagged for review.
Callers in ingested source are linked automatically. For classic ASP, Office macros or scripts that are not ingested, PYD ENTERPRISES lists the ProgIDs and methods to search for, and you can add found callers to the inventory.
Controls are parsed like other VB6 components. Their UI behavior is classified as presentation, while any business logic inside them is extracted as rules.
Request a codebase scan and review extracted rules, contracts and fixtures for your own VB6 COM / ActiveX estate, inside your VPC.