Vai al contenuto

Cos'è COM e cosa sono le API COM

Nello sviluppo per SAP Business One, sentirai continuamente parlare di COM, COM Interop, oggetti unmanaged, [STAThread] e ReleaseComObject.

Comprendere cosa sia COM è fondamentale: spiega il motivo per cui l'SDK di SAP si comporta in modo diverso rispetto alle consuete librerie .NET moderne.


1. Cos'è COM (Component Object Model)?

COM (Component Object Model) è una tecnologia introdotta da Microsoft negli anni '90 per consentire a componenti software scritti in linguaggi diversi (C++, Visual Basic 6, Delphi, .NET) di comunicare tra loro sullo stesso computer.

COM non è un linguaggio né un framework, ma uno standard binario (ABI - Application Binary Interface): definisce regole precise su come gli oggetti risiedono in memoria e come invocare i loro metodi, a prescindere dal compilatore utilizzato per crearli.

flowchart TD
    subgraph Managed [Mondo Gestito: .NET Framework]
        App["Applicazione Add-on C#<br/><i>(Codice gestito con Garbage Collector)</i>"]
        RCW["Runtime Callable Wrapper (RCW)<br/><i>(Proxy .NET che gestisce il Marshalling)</i>"]
        App -->|"Chiamata a metodo C#"| RCW
    end

    subgraph COM [Livello COM Interop: C++ Nativo]
        UIAPI["SAPbouiCOM.dll<br/><b>UI API</b>"]
        DIAPI["SAPbobsCOM.dll<br/><b>DI API</b>"]
        RCW -->|"Chiamata binaria COM"| UIAPI
        RCW -->|"Chiamata binaria COM"| DIAPI
    end

    subgraph Core [SAP Business One]
        Client["Client SAP Business One<br/><i>(Processo nativo a 64 bit)</i>"]
        DB[("Database Aziendale<br/><i>(SAP HANA / SQL Server)</i>")]
        UIAPI -->|"Eventi UI / Socket locale"| Client
        DIAPI -->|"Transazioni di business"| DB
    end

2. Perché SAP Business One usa le API COM?

Il nucleo del client di SAP Business One e il suo motore di business logic sono storicamente sviluppati in C e C++ nativo (codice unmanaged, cioè non gestito dal Garbage Collector di .NET).

Per consentire a partner e sviluppatori di estendere il programma usando linguaggi come C# o VB.NET senza dover scrivere codice C++ a basso livello, SAP ha esposto le sue funzionalità come server COM:

  • SAPbouiCOM (UI API): libreria COM per controllare l'interfaccia grafica del client SAP.
  • SAPbobsCOM (DI API): libreria COM per leggere e scrivere documenti e anagrafiche nel database.

3. Come dialoga C# con una libreria COM (COM Interop e RCW)

Quando in Visual Studio aggiungi un riferimento a una libreria COM, il runtime .NET crea un RCW (Runtime Callable Wrapper).

L'RCW è una classe proxy C# trasparente: quando chiami un metodo come oOrder.Add(), il codice C# parla con l'RCW, il quale: 1. Converte i tipi di dato gestiti (.NET) nei tipi binari nativi attesi da COM (Marshalling). 2. Invoca la funzione C++ nativa all'interno delle DLL di SAP. 3. Riconverte il risultato restituito nel mondo .NET.


4. Le conseguenze pratiche per chi sviluppa in C

Molte delle "stranezze" dell'SDK di SAP Business One dipendono proprio dalla natura COM dell'infrastruttura sottostante:

A. Perché la DI API usa codici di errore e non eccezioni?

In COM, i metodi non lanciano eccezioni come in C#. Tradizionalmente restituiscono un codice numerico di stato (chiamato storicamente HRESULT o codice d'errore intero).
Ecco perché in SAP si controlla il ritorno numerico:

int result = oOrder.Add();
if (result != 0)
{
    string errore = oCompany.GetLastErrorDescription();
}

B. Gestione della Memoria: Garbage Collector vs Conteggio Riferimenti

  • In C#: la memoria è gestita automaticamente dal Garbage Collector (GC).
  • In COM: gli oggetti rimangono vivi finché il loro conteggio di riferimenti interno (Reference Count) non scende a zero.

L'RCW di .NET tiene vivo l'oggetto COM nativo fino a quando il GC non decide di ripulirlo. Se usi oggetti molto pesanti in cicli intensivi (come Recordset), la memoria nativa potrebbe non essere rilasciata subito. In questi casi si usa esplicitamente il rilascio manuale COM:

System.Runtime.InteropServices.Marshal.ReleaseComObject(oRecordset);
oRecordset = null;

C. Perché serve [STAThread]?

COM prevede modelli di threading chiamati Apartment: - STA (Single Thread Apartment): garantisce che tutti gli accessi all'oggetto avvengano dallo stesso thread che lo ha creato. - MTA (Multi Thread Apartment): accessi concorrenti da più thread.

La UI API di SAP B1 è vincolata a un modello ad appartamento singolo (STA). Se lanci chiamate UI da thread paralleli senza marshalling, COM solleverà errori o farà crashare l'add-on.

D. Architettura dei processi: 32 bit vs 64 bit

Un processo a 32 bit non può caricare o interagire direttamente nello stesso spazio di memoria con una DLL COM compilata a 64 bit. Con SAP B1 10.0 (a 64 bit), l'add-on C# deve necessariamente essere compilato come x64.

E. Perché serve Embed Interop Types = False?

Se abilitata, questa funzionalità del compilatore .NET incorpora i tipi COM direttamente nell'assembly dell'add-on. Con SAP, questo impedisce al nuovo SDK Framework (SAPbouiCOM.Framework) di riconoscere e convertire correttamente le istanze provenienti da SAPbouiCOM, generando eccezioni di tipo InvalidCastException.


Caratteristica Librerie .NET Pure API COM di SAP B1
Linguaggio di origine C#, VB.NET, F# C / C++ nativo
Gestione memoria Garbage Collector Conteggio riferimenti (Reference Counting)
Segnalazione errori Eccezioni .NET (try/catch) Codici di ritorno numerici
Threading Libero (multithreading standard) Vincolato a Single Thread Apartment (STA)
Interfaccia Assembly .NET (.dll) Type Library COM registrata in Windows