Search code examples
c++dllc++builderdllimportdllexport

How do I write the body of a function in a dll, but have the prototype in my main program


Sorry if the question is rudimentory, I'm new to .dll-s. Basically I want to allow my function to have access to the same global variables it does in the main program it's originally defined in while actually being written in the .dll

example: I have a ListView object into which I am printing messages from within the function

void example(){
//Display is my listview
Display->Items->Add("Hello world");
}

in this example Display is a TListView object which is inicialized in my main.cpp from which I define the behavior of my VCL application form. This Display object is a global variable in the main cpp and because of it when I cut the example() and paste it into my new dll it breaks because within the range of the dll the Display doesn't exist.

My idea is to declare the function prototype void example(); in the main.h and SOMEHOW write the body in my dll, but when I include<"anything"> into the dll the compiler screams that idk what I'm trying to do...

What are my options?

I'm using c++ builder but I presume the same logical question would apply to any IDE


Solution

  • You are going about this all wrong. A DLL can't access variables that are outside of it, like in the main EXE, unless outside code gives the DLL pointers/references to them. Which won't help you anyway in the example you provided.

    A better design is to not have the DLL access the variables directly at all. In your example, you should make the EXE pass a pointer to a callback function to the DLL, which the DLL can then call when needed. Internally, that function can use the EXE's variables as needed.

    For example:

    MyDLL.h

    #ifndef MyDLL_H
    #define MyDLL_H
    
    #ifdef BUILDING_DLL
    #define MY_API __declspec(dllexport)
    #else
    #define MY_API __declspec(dllimport)
    #endif
    
    typedef void (__stdcall *myTextCallback)(const char *text, void *userData);
    
    MY_API void __stdcall dll_setTextCallback(myTextCallback userCallback, void *userData);
    
    #endif
    

    MyDll.cpp

    #define BUILDING_DLL
    #include "MyDll.h"
    
    myTextCallback textCallback = NULL;
    void *textCallbackData = NULL;
    
    void __stdcall dll_setTextCallback(myTextCallback userCallback, void *userData)
    {
        textCallback = userCallback;
        textCallbackData = userData;
    }
    
    void doSomething()
    {
        ...
        if (textCallback)
            textCallback("Hello World", textCallbackData);
        ...
    }
    

    EXE

    #include "MyDll.h"
    
    void __stdcall displayText(const char *text, void *userData)
    {
        TListItem *Item = static_cast<TMainForm*>(userData)->Display->Items->Add();
        Item->Caption = text;
    }
    
    __fastcall TMainForm::TMainForm(TComponent *Owner)
        : TForm(Owner)
    {
        dll_setTextCallback(&displayText, this);
    }
    
    __fastcall TMainForm::~TMainForm()
    {
        dll_setTextCallback(NULL, NULL);
    }
    

    This way, the DLL doesn't have to know or care what what the EXE wants to do with the DLL's data.