View Single Post
Old 2nd January 2020, 14:19   #7  |  Link
stax76
Registered User
 
stax76's Avatar
 
Join Date: Jun 2002
Location: On thin ice
Posts: 6,837
In a C++ test app it performs as expected, code:

Code:
#include <Windows.h>
#include <ComDef.h>

#include <iostream>
#include <string>
#include <atomic>
#include <chrono>

using namespace std;


// {864C3D72-B6FD-4014-8AB4-55B664FAEF2C}
static const GUID CLSID_BasicServer =
{ 0x864c3d72, 0xb6fd, 0x4014, { 0x8a, 0xb4, 0x55, 0xb6, 0x64, 0xfa, 0xef, 0x2c } };

// {177D3798-3D6D-4217-B355-D2355884CFDF}
static const GUID IID_IBasicServer =
{ 0x177d3798, 0x3d6d, 0x4217, { 0xb3, 0x55, 0xd2, 0x35, 0x58, 0x84, 0xcf, 0xdf } };


struct IBasicServer : IUnknown
{
    virtual int __stdcall GetFive() = 0;
};


class BasicServer : IBasicServer
{

private:

    std::atomic<int> m_refs = 0;

public:

    // IUnknown

    HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();

    // IBasicServer

    int     __stdcall GetFive();
};


// IUnknown

STDMETHODIMP BasicServer::QueryInterface(const IID& iid, void** ppv)
{
    if (!ppv)
        return E_POINTER;

    if (iid == IID_IUnknown)
    {
        *ppv = (IUnknown*)this;
    }
    else if (iid == IID_IBasicServer)
    {
        *ppv = (IBasicServer*)this;
    }
    else
    {
        *ppv = nullptr;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}


STDMETHODIMP_(ULONG) BasicServer::AddRef()
{
    return ++m_refs;
}


STDMETHODIMP_(ULONG) BasicServer::Release() {
    int refs = --m_refs;

    if (!refs)
        delete this;

    return refs;
}


// IBasicServer

int __stdcall BasicServer::GetFive()
{
    return 5;
}


// Extern

extern "C" {
    __declspec(dllexport) LPVOID __stdcall
    CreateBasicServer()
    {
        BasicServer* pServer = new BasicServer();
        LPVOID pIBasicServer;

        if (FAILED(pServer->QueryInterface(IID_IBasicServer, &pIBasicServer)))
            return nullptr;

        return pIBasicServer;
    }

    __declspec(dllexport) LPVOID __stdcall
    CreateBasicServerSlow()
    {
        return (IBasicServer*) new BasicServer();
    }
}

int main()
{
    // measure fast CreateBasicServer()
    auto start = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < 1'000'000; i++)
        ((IUnknown*)CreateBasicServer())->Release();

    auto end = std::chrono::high_resolution_clock::now();

    cout << "fast: " << (end - start).count() << endl;


    // measure slow CreateBasicServerSlow()
    auto start2 = std::chrono::high_resolution_clock::now();

    for (size_t i = 0; i < 1'000'000; i++)
        ((IUnknown*)CreateBasicServerSlow())->Release();

    auto end2 = std::chrono::high_resolution_clock::now();

    cout << "slow: " << (end2 - start2).count() << endl;

    cout << '\n' << "Press key to exit" << endl;
    cin.get();
}
If I create a C++ DLL and test it in a C# app it's 350 times slower!

Code:
#include "pch.h"

#include <ComDef.h>

#include <atomic>


// {864C3D72-B6FD-4014-8AB4-55B664FAEF2C}
static const GUID CLSID_BasicServer =
    { 0x864c3d72, 0xb6fd, 0x4014, { 0x8a, 0xb4, 0x55, 0xb6, 0x64, 0xfa, 0xef, 0x2c } };

// {177D3798-3D6D-4217-B355-D2355884CFDF}
static const GUID IID_IBasicServer =
    { 0x177d3798, 0x3d6d, 0x4217, { 0xb3, 0x55, 0xd2, 0x35, 0x58, 0x84, 0xcf, 0xdf } };


struct IBasicServer : IUnknown
{
    virtual int __stdcall GetFive() = 0;
};


class BasicServer : IBasicServer
{

private:

    std::atomic<int> m_refs = 0;

public:

    // IUnknown

    HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    ULONG   __stdcall AddRef();
    ULONG   __stdcall Release();

    // IBasicServer

    int     __stdcall GetFive();
};


// IUnknown

STDMETHODIMP BasicServer::QueryInterface(const IID& iid, void** ppv)
{
    if (!ppv)
        return E_POINTER;

    if (iid == IID_IUnknown)
    {
        *ppv = (IUnknown*)this;
    }
    else if (iid == IID_IBasicServer)
    {
        *ppv = (IBasicServer*)this;
    }
    else
    {
        *ppv = nullptr;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}


STDMETHODIMP_(ULONG) BasicServer::AddRef()
{
    return ++m_refs;
}


STDMETHODIMP_(ULONG) BasicServer::Release() {
    int refs = --m_refs;

    if (!refs)
        delete this;

    return refs;
}


// IBasicServer

int __stdcall BasicServer::GetFive()
{
    return 5;
}


// Extern

extern "C" {
    __declspec(dllexport) LPVOID __stdcall
    CreateBasicServer()
    {
        BasicServer* pServer = new BasicServer();
        LPVOID pIBasicServer;
        pServer->QueryInterface(IID_IBasicServer, &pIBasicServer);
        return pIBasicServer;
    }

    __declspec(dllexport) LPVOID __stdcall
    CreateBasicServerSlow()
    {
        return (IBasicServer*) new BasicServer();
    }
}
Code:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        // test fast
        Stopwatch sw = new Stopwatch();
        sw.Start();

        for (int i = 0; i < 1000; i++)
            Marshal.ReleaseComObject(CreateBasicServer());

        sw.Stop();
        Console.WriteLine("fast: " + sw.ElapsedMilliseconds);


        // test slow
        sw.Reset();
        sw.Start();

        for (int i = 0; i < 1000; i++)
            Marshal.ReleaseComObject(CreateBasicServerSlow());

        sw.Stop();
        Console.WriteLine("slow: " + sw.ElapsedMilliseconds);

        Console.ReadKey();
    }

    [DllImport(@"D:\Projekte\CPP\FrameServer\x64\Debug\FrameServer.dll")]
    static extern IBasicServer CreateBasicServer();

    [DllImport(@"D:\Projekte\CPP\FrameServer\x64\Debug\FrameServer.dll")]
    static extern IBasicServer CreateBasicServerSlow();
}

[Guid("177D3798-3D6D-4217-B355-D2355884CFDF")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IBasicServer
{
    [PreserveSig]
    int GetFive();
}
result:

fast: 8
slow: 2815

Last edited by stax76; 2nd January 2020 at 14:22.
stax76 is offline   Reply With Quote