1

This is an elaboration to an earlier question: How to reset state machines when unit testing C
There is also a similar question but i don't the answer match my problem and i have some examples i wish to present: Exporting a function pointer from dll

I have two sets of code that i expect should do the same but the latter crashes. Using mingw32 and Win7.

The function to be exported. This is to be considered legacy and unmutable.
addxy.c

    int addXY(int x, int y)
    {
      return x + y;
    }    

addxy.h

    int addXY(int x, int y);

The working example

main.c

    #include <stdio.h>
    #include "addxy.h"

    typedef int (__cdecl *addXYWrap_t)(int a, int b);

    addXYWrap_t addXYWrap = (addXYWrap_t)addXY;

    void main()
    {
      printf("result: %d", addXYWrap(3, 4));
    }

Yielding

result: 7

The crashing example

addxydll.c

    #include <stdio.h>
    #include "addxy.h"

    typedef int (__cdecl *addXYWrap_t)(int a, int b);

    __declspec(dllexport) addXYWrap_t addXYWrap = (addXYWrap_t)addXY;

main.c

    #include <windows.h>
    #include <stdio.h>

    typedef int (__cdecl *func)(int a, int b);

    void main()
    {
      HINSTANCE loadedDLL = LoadLibrary("addxy.dll");

      if(!loadedDLL) {
        printf("DLL not loaded");
        return;
      } else {
        printf("DLL loaded\n");
      }

      func addition = (func)GetProcAddress(loadedDLL, "addXYWrap");

      if(!addition) {
        printf("Func not loaded");
        return;
      } else {
        printf("Func loaded\n");
      }

      printf("result: %d", addition(3, 4));
    }

Yielding

DLL loaded
Func loaded

before it chrashes.

The crash gives no information as to why or what.
Is it a syntactical error or conceptional one?

Community
  • 1
  • 1
Enok82
  • 163
  • 1
  • 13
  • `__declspec(dllexport)` is to specify that you're exporting the function. In this case you're neither importing or exporting since you're doing a runtime lookup so remove the specifier. – Olipro Nov 12 '15 at 08:28
  • `GetProcAddress(loadedDLL, "addXYWrap");` <- this gives you the *address of* addXYWrap - it returns a `func*`, not a `func`! – user253751 Nov 12 '15 at 08:30
  • @immibis func is already a function pointer type. – Olipro Nov 12 '15 at 08:30
  • @Olipro Yeah, and in this case GetProcAddress returns a pointer to a function pointer. – user253751 Nov 12 '15 at 08:36
  • @immibis Ah yes, correct. He should be exporting the function itself rather than the function pointer. Or alternatively he can dereference the `GetProcAddress()` result of course. – Olipro Nov 12 '15 at 08:40
  • @Olipro my reason for not exporting the function itself is that i have no control over `addxy.c`and `addxy.h` which makes it difficult to change the declaration of `addXY(int x, int y)`. Another reason that i did not mention is that from time to time i might need to export a function that is not in the legacy code header, only in the source. It's for testing purposes. – Enok82 Nov 12 '15 at 08:50
  • @Enok82 So what? Then just create a wrapper function around it, not a function pointer. `__declspec(dllexport) int myAddXY(int x, int y) { return addXY(x, y); }` – Olipro Nov 12 '15 at 08:52
  • @Olipro i did that in my previous solution to my question mentioned in the beginning. I did however want to try this version as well since i feel it gives a cleaner look if there are more than only one function to be exported. Also, since it's apparently not wrong to do it like this, just for kicks! ;) – Enok82 Nov 12 '15 at 08:59
  • @Enok82 well, it works. I would argue it's "wrong" on the basis of it being unnecessary and will result in an unecessary extra CPU instruction in order to make the call. – Olipro Nov 12 '15 at 09:05

3 Answers3

2
func addition = (func)GetProcAddress(loadedDLL, "addXYWrap");

This call to GetProcAddress returns the address of addXYWrap, not its value. Since addXYWrap is a function pointer (of the same type as func), that means it returns a pointer to a function pointer, or a func*.

Try changing that line to this:

func addition = *(func*)GetProcAddress(loadedDLL, "addXYWrap");

 

Or, alternatively:

func* addition = (func*)GetProcAddress(loadedDLL, "addXYWrap");

and then (*addition)(3, 4)

user253751
  • 57,427
  • 7
  • 48
  • 90
1

So, based on comments above, you appear to be overthinking it. If you did need a function pointer, then to correctly call it, you must first dereference GetProcAddress like so:

func addition = *(func*)GetProcAddress(loadedDLL, "addXYWrap");

However, a much more convenient solution is to just wrap the function:

__declspec(dllexport) int myAddXY(int x, int y)
{
    return addXY(x, y);
}
Olipro
  • 3,489
  • 19
  • 25
-1
int addXY(int x, int y)
{
  return x + y;
}
__declspec(dllexport) addXYWrap_t addXYWrap = (addXYWrap_t)addXY;

This is an error. You have to export function, not a global pointer. That is,

/* addxy.c */
__declspec(dllexport) int addXY(int x, int y)
{
  return x + y;
}
....
/* main.c */
func addition = (func)GetProcAddress(loadedDLL, "_addXY");
Matt
  • 13,674
  • 1
  • 18
  • 27