c++windowsdelphi-7dllexportwgl

Passing HWND from Delphi 7 to C++ DLL


I have a Delphi 7 application that tries to render an OpenGL scene into a TPanel by passing the property Handle of the TPanel to a C++ DLL (written in Visual Studio 2008). Here's the DLL function contract:

#pragma once
#ifdef QMM_EXPORTS
#define QMM_API __declspec(dllexport)
#else
#define QMM_API __declspec(dllimport)
#endif

extern "C" QMM_API int getParam (int key);
extern "C" QMM_API float getParamF (int key);
extern "C" QMM_API char *getParamS (int key);

#include <gl/gl.h>

extern "C" QMM_API int setGlRenderTo (HWND hwnd);
extern "C" QMM_API void glRenderTest ();

The DLL code looks like this:

int setGlRenderTo (HWND hwnd) {
    GLuint      PixelFormat; 

    doLog('D',"setGlRenderTo(): start (hwnd=%i)", hwnd->unused);
    if (hwnd != NULL && currHWND == hwnd) {
        doLog('W', "setGlRenderTo(): hwnd == currHWND, ignoring");
        return 0;
    }

    if (currRC != NULL) {       
        doLog('D', "setGlRenderTo(): releasing currRC...");
        wglMakeCurrent(NULL,NULL);
        wglDeleteContext(currRC);
        currHWND = NULL;
    }

    if (currDC != NULL) {
        doLog('D', "setGlRenderTo(): releasing currDC...");
        ReleaseDC(currHWND,currDC);
        currHWND = NULL;
    }

    currDC = GetDC(hwnd);
    if (!currDC) {
        doLog('E', "setGlRenderTo(): Failed to get a valid DC, aborting");
        return 1;

    }

    currHWND = hwnd;
    PIXELFORMATDESCRIPTOR pfd =
    {
        sizeof(PIXELFORMATDESCRIPTOR),
        1,
        PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,  
        PFD_TYPE_RGBA,       
        32,                   
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        0, 0, 0, 0,
        24,                   
        8,                   
        0,                   
        PFD_MAIN_PLANE,
        0,
        0, 0, 0
    };

    if (!(PixelFormat=ChoosePixelFormat(currDC,&pfd))) {
        doLog('E', "setGlRenderTo(): Failed to get a valid pixel format, aborting");
        return 1;
    }

    if (!SetPixelFormat(currDC, PixelFormat, &pfd)) {
        doLog('E', "setGlRenderTo(): Failed to set pixel format, aborting");
        return 1;
    }

    if (!(currRC=wglCreateContext(currDC))) {
        doLog('E', "setGlRenderTo(): Failed to create OpenGL rendering context, aborting");
        return 1;
    }

    if (!wglMakeCurrent(currDC,currRC)) {
        doLog('E', "setGlRenderTo(): Failed to switch to OpenGL rendering context, aborting");
        return 1;
    }

    return 0;
}

On the Delphi 7 side, I have the DLL call mapped like this:

function setGlRenderTo (handler : HWND) : integer; external 'qmm.dll';

My DLL code fails when I try to create a DC context (at the line currDC = GetDC(hwnd);).

I already tried to change the type to LongWord in the Delphi side, and unsigned int in the DLL. Also, I tried to just pass it as Integer (Delphi side) and int (C++ side). No success in any of the tests.


Solution

  • On the C++ side, no calling convention is being specified explicitly in the function declarations, so the C++ compiler will default to __cdecl.

    On the Delphi side, you are not specifying any calling convention on the imported DLL function, so the Delphi compiler will default to register - which is not compatible with any calling convention that Visual Studio supports. So the DLL does not receive the HWND parameter correctly.

    You need to add cdecl to the function declaration on the Delphi side:

    function setGlRenderTo (handler : HWND) : integer; cdecl; external 'qmm.dll';
                                                       ^^^^^