5

First of all yes I have searched this for a while now and can't find any answers relevant to my case. Basically I am trying to get the address of a function in a windows DLL (dnsapi.dll) and GetProcAddress is returning 0. After a while of scratching my head I even went on to create a program which simply uses GetProcAddress of MessageBox in user32.dll. Same result. Here is the code of the second program I made which still doesn't work:

#include <stdio.h>
#include <Windows.h>

int main() {
    HINSTANCE hLib = LoadLibrary(TEXT("user32.dll"));
    DWORD MsgBoxAddr = (DWORD)GetProcAddress(hLib, "MessageBox");

    printf("%ld", MsgBoxAddr);
    getchar();

    return 0;
}

BTW GetLastError returns 127 which seems to be the most common error returned when GetProcAddress doesn't work but I can't figure out what is wrong, I have tried with many functions and DLL's, not just these couple.

Thanks. :)

EDIT: The linked article solved my problem, the functions I tried all had unicode and anis versions (w and a). Using the full API names solved the problems. Thanks for linking that question.

Thank you.

Rob Lennon
  • 63
  • 5
  • This question is not a duplicate of https://stackoverflow.com/questions/12813679/getprocaddress-returning-null-for-regdeletekeyex. That question is basically an answer related to A/W versions of functions in WinAPI but GetProcAddress' issue is not related to that because it doesn't have A/W versions. – Brian Hawk May 07 '18 at 00:43

2 Answers2

5

Some common APIs are not the real names of the functions, including LoadLibrary and MessageBox. All those functions don't exist!

Thats because most Windows APIs that take text as parameter will have two versions of each, one that accepts ANSI text and other that accept UNICODE text. Those "functions" you know are actually preprocessor macros that will route you to the right function automatically depending on your Visual Studio project's default charset.

MessageBox for instance, don't exist. What exist are the functions MessageBoxA and MessageBoxW, one for ANSI other for UNICODE. So this is how you will get their address:

ANSI:

HINSTANCE hLib = LoadLibraryA("user32.dll");
DWORD MsgBoxAddr = (DWORD)GetProcAddress(hLib, "MessageBoxA");

UNICODE:

HINSTANCE hLib = LoadLibraryW(L"user32.dll");
DWORD MsgBoxAddr = (DWORD)GetProcAddress(hLib, "MessageBoxW");

Automatic:

HINSTANCE hLib = LoadLibrary(TEXT("user32.dll"));
#ifdef UNICODE
DWORD MsgBoxAddr = (DWORD)GetProcAddress(hLib, "MessageBoxW");
#else
DWORD MsgBoxAddr = (DWORD)GetProcAddress(hLib, "MessageBoxA");
#endif
Havenard
  • 27,022
  • 5
  • 36
  • 62
  • GetProcAddress doesn't have A/W versions. – Brian Hawk May 05 '18 at 21:26
  • @BrianHawk mmm... looks like you are right. Interesting, I thought every Windows API that handles string had the two variations. But it does make sense, after all, the names of exported functions is always in ASCII for every DLL. – Havenard May 06 '18 at 02:32
2

Havenard already gave the answer, so don't accept mine (but do read it).

A better way to solve it is to define:

#ifndef _CRT_STRINGIZE  // Might be already defined in crtdefs.h, but if not...
#define __CRT_STRINGIZE(Value) #Value
#define _CRT_STRINGIZE(Value) __CRT_STRINGIZE(Value)
#endif

and then use

GetProcAddress(hLib, TEXT(_CRT_STRINGIZE(MessageBox)));
user541686
  • 205,094
  • 128
  • 528
  • 886