Re: Help with DLL's & CALLBACKS

From: Joseph M. Newcomer (newcomer_at_flounder.com)
Date: 07/24/04


Date: Sat, 24 Jul 2004 16:53:20 -0400

The client program would not be in the DLL's header. But how could you consider calling a
DLL if you didn't have the function prototype for the functions to call? This requires
putting the declarations of the DLL's functions in a header file which is included by the
client; I cannot imagine any other way it would make sense. If you think it makes sense to
hand-code the extern declarations for each function each time, go back and read some
introductory textbook on programming methodology. You want exactly ONE point of definition
of the interface to the DLL, and we call that a "header file". Where you put it is up to
you, but if it gets "misplaced" then somebody has screwed up royally and you should not be
worrying about the ways in which people can make fundamental mistakes such as "losing"
critical pieces of source code required to compile their system.

In any case, there is no reason to assume that every thread is going to use the same
callback on every call, so making it a static extern variable makes no sense. You didn't
actually do this, anyway, because I saw you clearly passing in the callback address to the
function, so the "extern" declaration appears to be simply noise and should be eliminated.

I have done many plugins with callbacks, and not once have I worried about these issues. I
have not needed static variables, I have not ever worried about "losing" critical pieces
of source code (which would simply fall into the class of "irresponsible programming" and
therefore is easily dismissed). And the client has no clue which plugins are being used.
But it DOES need to have prototypes for the interfaces, even if they are obtained by
GetProcAddress.

Your code looked fine in terms of passing in the callback function and an arbitrary value
(modulo making it either LPVOID or UINT_PTR).

If I need to retain the function pointer across multiple calls, I usually require the
caller call some Initialize... or Open... or similarly-named call, which returns a type
HANDLE (or some specific opaque type whose deifnition is not known). In that, I put the
callback pointer. On each subsequent request, the client presents this HANDLE (or opaque
pointer) to the function, and the function casts it back to some known internal structure
and uses it, and thus gets access to the callback pointer. A Release... or Close... call
releases the storage. At no time does the client need to see the actual data type details
(remember: there is no reason to think that a DLL has "An" interface; it can have as many
header files as necessary, some of which are used internally and some of which are
exported interfaces. The actual structure would be in the private interface to the plugin,
and the public interface would contain only a reference to that structure.

private.h:
#include "public.h"
class Whatever {
            public:
                   Whatever(CallbackFunction f) { func = f; }
            protected:
                  CallbackFunction func;
                   ... other declarations here
};

public.h:
class Whatever;
typedef void (CALLBACK * CallbackFunction)(int x, int y);

typedef Whatever * (*OpenPluginProc)(CallbackFunction);

typedef void (*ClosePluginProc)(Whatever *);
#define OPEN_PLUGIN "OpenPlugin"
#define CLOSE_PLUGIN "ClosePlugin"

whatever.dll:

Whatever * OpenPlugin(CallbackFunction f)
     {
       Whatever * result = new Whatever(f);
        ....
       return result;
     }

void ClosePlugin(Whatever * w)
   {
     delete w;
   }

The client:

#include "public.h"

....
     HANDLE h = LoadLibary("WhateverCompatiblePlugin.dll");
     OpenPluginProc open = GetProcAddress(OPEN_PLUGIN);
     Whatever * w = open(MyCallback);

....
    ClosePluginProc close = GetProcAddress(CLOSE_PLUGIN);
     close(w);

(Error detection and generalization to other itnerfaces left as An Exercise For The
Reader)
                                

Note that if you have 19 DLLs, Each DLL can have its own private version of a Whatever
structure, e.g.,

private14.h

class Whatever14 : public Whatever {
...plugin-specific stuff here
};

Also note that there is no reason a callback function needs to have a CALLBACK linkage. It
can have any linkage type you want, including CDECL. CALLBACK linkages are one kind of
callback, but a callback is whatever you want it to be!

Note that in a GUI program, I would be more inclined to use a message-based mechanism for
notifications from the callbacks, such as I use in my "instrument plugins" that I did for
one client (a piano keyboard, a music score, and a guitar fretboard, all with wildly
different internal structure but the same external interface)
                                        joe

On Sat, 24 Jul 2004 06:09:03 -0700, raykos <raykos@discussions.microsoft.com> wrote:

>Hello Joe,
>
> Thanks for the response. And yes, if I read you correctly,"...It suggests that every possible thread is going to use the same callback.", that is what I want to
>do. I don't want to have to include in the client program the dll's header, and I
>don't want to have to include in the dll the clients header; because, if at some time, either one of the headers gets lost or is not where it's supposedto be, problems occur.
> The plug-in is going to be loaded at run time, and I do want the plug-in to be able
>to say, "I don't know who's using me, but if you'll give me a callback address, I'll
>use that to keep you informed of what's going on". And on the client side, (since at
>compile time, the client program doesn't know what plug-in the user is going to
>choose), it can say to the loaded plug-in, "keep me informed by using this callback".
> Maybe I'm going about this all wrong, and maybe, if I've explained what I'm trying
>to do well enough, you could suggest some different code? Any help appreciated...
>
>TIA,
>
>Ray K.
>
>

Joseph M. Newcomer [MVP]
email: newcomer@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm



Relevant Pages

  • Re: Ever had to judge a new to-be-hired in interview?
    ... My own ccrpTimers (DLL) were used by thousands of apps, ... >>> What kind of callback are you using? ... interface for the client to implement. ...
    (microsoft.public.vb.general.discussion)
  • Re: Calling a client function back from a DLL
    ... the callback that the client might provide to the DLL would have a prototype like this: ... The pContext can point to some context data structure that the client callback could use. ...
    (microsoft.public.vc.language)
  • Callback example -- Managed C++ and Unmanaged DLL (C++)
    ... Can someone please post a small/simple working example of doing a callback ... I have a function in MC++ client that needs to get fired ... dealing with P/Invoke), but can't seem to find a simple example of doing a ... callback with MC++ (using DllImport) and a C++ DLL. ...
    (microsoft.public.dotnet.languages.vc)
  • Re: Importing functions/Variable from DLL
    ... and we dont need to use __declspecin the client. ... Using a header is a good way but not required and not enough - you at least ... Does MFC DLLs support exporting of variables?? ... At least in VC6 the example vanilla DLL project demonstrated this. ...
    (microsoft.public.vc.language)
  • Re: Marshalling std Picture
    ... Yes I suppose I could simply callback the client and ... let it know disk files a ready but I'm trying to DLL ... all that and simply pass the client the jpg's. ...
    (microsoft.public.vb.general.discussion)

Quantcast