Search code examples
c++functiontypedefstdcall

TypeDef with Function Pointer: Function does not Exist


The problem is running code on an older machine where a requested function does not exist. To check for it one uses LoadLibrary and GetProcAddress as demonstrated here, but GetProcAddress requires the address of the functions in a TypeDef prior to its use.
For example, take these two on e.g, XP SP2 32 bit:

typedef BOOL (__stdcall *LPFN_Wow64RevertWow64FsRedirection) (PVOID OldValue);
typedef BOOL (__stdcall *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
...

...
LPFN_Wow64RevertWow64FsRedirection wowRevert = NULL;
LPFN_Wow64DisableWow64FsRedirection wowDisable = NULL;
HINSTANCE hLib;
if(GetProcAddresses( &hLib, "kernel32.dll", 2, &wowRevert,_ 
"Wow64RevertWow64FsRedirection", &wowDisable, Wow64DisableWow64FsRedirection" ))
{...

Code crashes here with:

The procedure entry point Wow64RevertWow64FsRedirection could not be located in the dynamic link library Kernel32.dll

It's easy enough to implement our own custom Wow64RevertWow64FsRedirection with non-WINAPI typedefs, but how can they be replaced with the base type when the function exists in kernel32.dll?


Solution

  • I'm having a bit of trouble understanding your question. The Wow64RevertWow64FsRedirection function is obviously not going to exist on a 32-bit operating system, so it won't exist on 32-bit Windows XP. Therefore, attempting to retrieve a pointer to this function with GetProcAddress will fail. You get the sensible error that this entry point could not be found. If the entry point cannot be found, the function does not exist and you should not attempt to call it.

    You claim that you can implement your own custom Wow64RevertWow64FsRedirection function, but I haven't the foggiest idea why you would want to do this. If the operating system supports WOW64 file-system redirection, then it will provide the Wow64RevertWow64FsRedirection function. If it does not, then it does not provide the function, but you do not need such a function, because there is no such thing as WOW64 file-system redirection. You don't need to enable, disable, or revert it.

    It seems that you are making this far more complicated than it needs to be. You don't even need to first verify that the process is a 64-bit process. You can just attempt to locate the entry point to Wow64RevertWow64FsRedirection (or Wow64DisableWow64FsRedirection, as needed), call it if it exists, or ignore the failure if it does not exist.

    It is as simple as:

    BOOL RevertWOW64RedirectionIfNecessary(PVOID pOldValue)
    {
        typedef BOOL (WINAPI * fnWow64RevertWow64FsRedirection)(PVOID);
    
        fnWow64RevertWow64FsRedirection pfn =
            reinterpret_cast<fnWow64RevertWow64FsRedirection>(
               reinterpret_cast<void*>(
               GetProcAddress(GetModuleHandle(L"kernel32"),
                              "Wow64RevertWow64FsRedirection")));
    
        if (pfn)
        {
            // The function exists, so call it through the pointer we obtained.
            return pfn(pOldValue);
        }
        else
        {
            // The function does not exist, so we can't call it.
            // But we don't ever need to call it in such cases,
            // so do nothing and feign success.
            return TRUE;
        }
    }
    

    Note that I am calling the GetModuleHandle function to retrieve a handle to the module kernel32.dll (the .dll extension is implied). I can use GetModuleHandle here instead of LoadModule because I know that kernel32.dll is guaranteed to always be loaded in any application's process. And since I've used GetModuleHandle, I don't need to free the module handle, either.

    I pass the resulting handle to the GetProcAddress function, along with a string that contains the name of the function/procedure whose address is to be retrieved. This function attempts to retrieve the address of that function, and returns it if it exists; otherwise, it fails and returns NULL.

    I check to see if it returned a valid pointer, and if so, I call the function dynamically through that pointer. Otherwise, it returned NULL, meaning that the function is not available, but in that case, we don't even need to worry about it, so the code just becomes a no-op.

    As for the funny casting, see my answer here, which explains this trick.