Skip to content
PYD ENTERPRISES

Migration guide

VB6 COM and ActiveX components to REST: contracts, transactions and the callers you forgot

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.

VB6 COM / ActiveXREST services
DIFFICULTY
High
OUTPUT
OpenAPI / YAML
SYNTAX TRAPS
5 covered
WORKFLOW
6 steps

By Pranav Kulkarni, Head of Language Engineering · Updated 15 Oct 2026

Technical syntax challenges

Where VB6 COM / ActiveX migrations go wrong.

01

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.

02

COM+ transactions and SetComplete or SetAbort

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.

03

Err.Raise with vbObjectError codes

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.

04

Variants and SAFEARRAYs at the boundary

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.

05

Unknown callers

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

6 steps from source to signed-off spec.

The sequence a PYD ENTERPRISES Discovery Scan runs for this stack. Every output links back to source file and line range.

  1. 1

    Ingest components, type libraries and known callers

    Provide the ActiveX projects (.vbp, .cls, .bas), compiled type libraries, COM+ catalog exports and the source of every client application you have.

  2. 2

    Resolve public interfaces

    PYD ENTERPRISES builds each class's public interface from source and type library, including ByRef outputs, optional parameters, default members and instancing settings.

  3. 3

    Map transactions and error contracts

    MTSTransactionMode, ObjectContext votes and every Err.Raise path are recorded per method, so transaction scope and error codes are part of the spec.

  4. 4

    Trace callers by ProgID and reference

    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.

  5. 5

    Extract rules inside the component

    Calculations and validations are sliced out of each method and exported as DMN tables, separate from COM and database plumbing.

  6. 6

    Export OpenAPI 3.1 and contract fixtures

    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

The source, and what PYD ENTERPRISES extracts from it.

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

clsPolicySvc.clsVB6
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 Long
6 Dim ctx As ObjectContext
7 Set ctx = GetObjectContext()
8 On Error GoTo Fail
9 If EffDate < Date Then
10 Err.Raise vbObjectError + 1001, "PolicySvc", "Backdated endorsement"
11 End If
12 NewPremium = RatePolicy(PolicyNo, EffDate)
13 Warnings = Array()
14 If NewPremium > 25000 Then Warnings = Array("UW_REVIEW")
15 ctx.SetComplete
16 Endorse = 0
17 Exit Function
18Fail:
19 ctx.SetAbort
20 Err.Raise Err.Number, Err.Source, Err.Description
21End Function

EXTRACTED ARTIFACT

endorsements.openapi.yamlYAML
1paths:
2 /policies/{policyNo}/endorsements:
3 post:
4 operationId: createEndorsement
5 x-pyd-source: clsPolicySvc.cls:2-21
6 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: object
13 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: array
25 items: { enum: [UW_REVIEW] }
26 "422":
27 description: vbObjectError + 1001, backdated endorsement

Architectural best practices

Build the REST services side to the spec, not to the old shape.

  • Publish the caller inventory with the contract and close every gap before switching a ProgID to a proxy or retiring it.
  • Return every ByRef output in the response body and version the API if a caller needs a different shape.
  • Replace distributed COM+ transactions with a documented consistency model; do not assume a single HTTP call gives the same guarantee.
  • Map each vbObjectError code to a stable HTTP status and machine-readable error type that callers can switch on.
  • Run the generated fixtures against the COM component and the REST service side by side until results match.

A shared component is a platform

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.

Reading the endorsement example

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

VB6 COM / ActiveX to REST services questions

Can PYD ENTERPRISES analyze compiled ActiveX DLLs without source?

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.

How are callers outside VB6 found?

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.

Does this cover ActiveX controls (.ocx) on forms?

Controls are parsed like other VB6 components. Their UI behavior is classified as presentation, while any business logic inside them is extracted as rules.

Get the spec for your VB6 COM / ActiveX estate.

Request a codebase scan and review extracted rules, contracts and fixtures for your own VB6 COM / ActiveX estate, inside your VPC.