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:
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:
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.
Riepilogo¶
| 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 |