So I took a look at mpusbapi.h and the example applications (from here, MCHPFUSB 1.3).
I'm going under the assumption that you are dynamically loading the functions at runtime with LoadLibrary
, as it appears their binaries were built with Borland's compiler, and thus the stub LIB won't work as-is in VS (unless you have a VS build, or want to just manually generate it).
The short answer is: The header as-is isn't really suitable to be included from multiple files. It sort of works in their simple example applications but that's about it, so you'll have to roll your own. Despite the implications of their "documentation", to maintain your sanity you'll want to view mpusbapi.h as more of an example than anything generally useful.
The medium answer is: The header is really poorly designed. In particular it defines global variables, thus every source file that includes it will have those defined, and thus, your error. The reason they got away with it is this: They built everything with Borland's tools, likely including their examples, and unlike most other compilers, multiple definitions are merely a warning with Borland's linker. So they probably ignored the warnings, since it still worked. Now you pay the price when you use a saner linker. (Also the library is very old, I don't remember what VS did about multiple definitions back in 2004 or whenever so it's also possible that it used to accept this.)
The long answer / solution is: The things in that header aren't function declarations or typedefs, they're actual definitions of function pointer variables (which you are responsible for initializing with GetProcAddress
). You have a lot of options but basically you're just going to want to start from scratch, using the function signatures given in the current header as a guide.
First, from the example applications (and I know you know this, but for the benefit of the general reader), here is how to load them dynamically. This applies in general cases as well:
void LoadDLL(void)
{
libHandle = NULL;
libHandle = LoadLibrary("mpusbapi");
if(libHandle == NULL)
{
printf("Error loading mpusbapi.dll\r\n");
}
else
{
MPUSBGetDLLVersion=(DWORD(*)(void))\
GetProcAddress(libHandle,"_MPUSBGetDLLVersion");
MPUSBGetDeviceCount=(DWORD(*)(PCHAR))\
GetProcAddress(libHandle,"_MPUSBGetDeviceCount");
MPUSBOpen=(HANDLE(*)(DWORD,PCHAR,PCHAR,DWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBOpen");
MPUSBWrite=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBWrite");
MPUSBRead=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBRead");
MPUSBReadInt=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBReadInt");
MPUSBClose=(BOOL(*)(HANDLE))GetProcAddress(libHandle,"_MPUSBClose");
if((MPUSBGetDeviceCount == NULL) || (MPUSBOpen == NULL) ||
(MPUSBWrite == NULL) || (MPUSBRead == NULL) ||
(MPUSBClose == NULL) || (MPUSBGetDLLVersion == NULL) ||
(MPUSBReadInt == NULL))
printf("GetProcAddress Error\r\n");
}//end if else
}//end LoadDLL
Note that, looking at that implementation and comparing it to the header, it doesn't actually load all of the functions from the DLL. It only loads the one that that specific example application needed. So don't forget to load the rest of the functions you use.
So (and again assuming manual run-time linking, if you've got a VS lib you can just skip all this, link to the LIB, and include _mpusbapi.h [note the underscore] but not mpusbapi.h).
Now, like I said there's a lot of options, but they all have the same goals:
- Define those function pointers once.
- Declare them in a header so you can use them elsewhere (mpusbapi.h makes the mistake of defining them in the header).
- When your program starts, populate the function pointers with
LoadLibrary
/GetProcAddress
as in the LoadDLL()
implementation above.
So do whatever floats your boat. Here's one quick and dirty-ish way to get the job done:
- Create some source file (perhaps the same one you put
LoadDLL()
or equivalent in) and copy + paste all those function pointer definitions from the current mpusbapi.h into it. That source is now where those globals will be defined.
Edit mpusbapi.h and add extern
in front of each definition, so that it merely becomes a declaration, e.g.:
extern DWORD (*MPUSBGetDeviceCount)(PCHAR pVID_PID);
You may now include your fixed mpusbapi.h anywhere you need to use those.
- Be sure and call
LoadDLL()
or whatever with LoadLibrary
/GetProcAddress
to load and initialize all your global function pointers once before you use any of them.
And that should do it. If you want to organize your code differently, wrap it all up in a class, possibly making those member vars and delegating to them, or generate and use a LIB instead of manually loading all the functions, etc., go right ahead, as long as you get the general steps done and don't define globals in a header that is included by multiple source files (or at all, in general).