Featured image of post How To Write an OLE Server in Raw C++

How To Write an OLE Server in Raw C++

Cause thats how we roll..no MFC Here...

Introduction: OLE, The Ancient Windows Magic

So, what is OLE? It’s basically a way to allow applications to talk to each other, like embedding an Excel spreadsheet into a Word document (you’ve seen that, right?).

It runs on top of COM (Component Object Model), which is another relic of Windows past that, believe it or not, still powers a lot of modern applications.

Now, there are two ways to write an OLE server:

  1. In-Process Server – This is a fancy way of saying “DLL.” The OLE server runs inside the same process as the client, making it faster but harder to isolate if something goes wrong.
  2. Out-of-Process Server – This is a standalone EXE that runs separately, meaning better isolation but slightly slower communication.

And this can be done in MFC, or just RAW C++.. the later is the one we will explore in this article..


Writing an In-Process OLE Server (DLL)

An in-process OLE server is a DLL that exposes some COM objects. We will create a simple calculator OLE server that lets a client add and subtract numbers.

Step 1: Define the COM Interface

We define a simple interface with two methods, Add and Subtract.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Calculator.idl
import "oaidl.idl";
import "ocidl.idl";

[ object, uuid(12345678-1234-1234-1234-123456789012), oleautomation ]
interface ICalculator : IUnknown
{
    HRESULT Add([in] int a, [in] int b, [out, retval] int* result);
    HRESULT Subtract([in] int a, [in] int b, [out, retval] int* result);
};

Step 2: Implement the OLE Server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Calculator.cpp
#include <windows.h>
#include "Calculator_h.h"

class Calculator : public ICalculator
{
    LONG refCount;
public:
    Calculator() : refCount(1) {}
    
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppv) override {
        if (riid == IID_IUnknown || riid == __uuidof(ICalculator)) {
            *ppv = static_cast<ICalculator*>(this);
            AddRef();
            return S_OK;
        }
        *ppv = nullptr;
        return E_NOINTERFACE;
    }
    
    ULONG __stdcall AddRef() override {
        return InterlockedIncrement(&refCount);
    }
    
    ULONG __stdcall Release() override {
        ULONG count = InterlockedDecrement(&refCount);
        if (count == 0) delete this;
        return count;
    }
    
    HRESULT __stdcall Add(int a, int b, int* result) override {
        *result = a + b;
        return S_OK;
    }
    
    HRESULT __stdcall Subtract(int a, int b, int* result) override {
        *result = a - b;
        return S_OK;
    }
};

Step 3: Register the Server

To make the DLL accessible, we need to register it using regsvr32. We implement DllRegisterServer.

1
2
3
4
STDAPI DllRegisterServer() {
    // Register CLSID and interfaces here (omitted for brevity)
    return S_OK;
}

Compile this as a DLL and register it using:

1
regsvr32 Calculator.dll

And that’s it! You now have a working in-process OLE server.


Writing an Out-of-Process OLE Server (EXE)

Out-of-process servers are basically standalone applications that expose COM objects. We use the same ICalculator interface but implement it in an EXE.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// CalculatorServer.cpp
#include <windows.h>
#include "Calculator_h.h"

class Calculator : public ICalculator { /* same as before */ };

int main() {
    CoInitialize(NULL);
    Calculator calc;
    // Register with COM runtime
    CoRegisterClassObject(__uuidof(Calculator), &calc, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &cookie);
    MessageBox(NULL, "Server running", "OLE Server", MB_OK);
    CoUninitialize();
    return 0;
}

Compile and register it with:

1
CalculatorServer.exe /RegServer

Calling the OLE Servers

From a client application, we can use CoCreateInstance to call either server.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Client.cpp
#include <windows.h>
#include "Calculator_h.h"

int main() {
    CoInitialize(NULL);
    ICalculator* calc;
    HRESULT hr = CoCreateInstance(__uuidof(Calculator), NULL, CLSCTX_ALL, IID_ICalculator, (void**)&calc);
    if (SUCCEEDED(hr)) {
        int result;
        calc->Add(3, 4, &result);
        printf("3 + 4 = %d\n", result);
        calc->Release();
    }
    CoUninitialize();
    return 0;
}

Key Ideas

ConceptExplanation
OLEObject Linking and Embedding, old-school inter-process communication
COMThe backbone of OLE, allows objects to interact
In-Process ServerA DLL-based COM server
Out-of-Process ServerAn EXE-based COM server
CoCreateInstanceFunction to instantiate a COM object

References