Ben
Ben

Reputation: 2937

LoadLibrary taking a LPCTSTR

I want to develop a plugin system using LoadLibrary.
My problem is: I want my function to take a const char* and LoadLibrary takes a LPCTSTR.
I had the bright idea to do (LPCSTR)path which kept giving me a module not found error.

Current code is below. If I uncomment the widepath = L.. line it works fine. I've read solutions using MFC but I'd like to not use MFC.

Current code:

bool PluginLoader::Load(char *path)
{
    path = "Release\\ExamplePlugin.dll";
    LPCTSTR widepath = (LPCTSTR)path;
    //widepath = L"Release\\ExamplePlugin.dll";

    HMODULE handle = LoadLibrary(widepath);
    if (handle == 0)
    {
        printf("Path: %s\n",widepath );
        printf("Error code: %d\n", GetLastError());

        return false;
    }

    int (*load_callback)() = (int (*)()) GetProcAddress(handle, "_plugin_start@0");

    if (load_callback == 0)
    {
        return false;
    }

    return load_callback() == LOAD_SUCCESS;
}

Upvotes: 10

Views: 15139

Answers (4)

Hans Passant
Hans Passant

Reputation: 942408

Use LoadLibraryA(), it takes a const char*.

Winapi functions that take strings exist in two versions, an A version that takes an Ansi string and a W version that takes a wide string. There's a macro for the function name, like LoadLibrary, that expands to either the A or the W flavor, depending if UNICODE is #defined. You are compiling your program with that #define in effect, so you get LoadLibraryW(). Simply cheat and use LoadLibraryA() explicitly.

Upvotes: 23

Jerry Coffin
Jerry Coffin

Reputation: 490713

The approved method with LoadLibrary is to not use a char const *, but instead use a TCHAR const *, and use the _T macro on all literals:

bool PluginLoader::Load(TCHAR const *path) {

    path = _T("Release\\ExamplePlugin.dll");

    HMODULE handle = LoadLibrary(path);
    if (handle == 0)
    {
        _tprintf(_T("Path: %s\n"),widepath );
        _tprintf(_T("Error code: %d\n"), GetLastError());

        return false;
    }

    int (*load_callback)() = (int (*)()) GetProcAddress(handle, _T("_plugin_start@0"));

    if (load_callback == 0)
    {    
        return false;
    }    
    return load_callback() == LOAD_SUCCESS;
}

This will automatically use LoadLibraryW when _UNICODE/UNICODE are defined, and LoadLibraryA when they're not. Likewise, _T will give narrow or wide string literals on the same basis, so it all stays in sync.

I generally prefer to use the W suffixed functions explicitly, and use the L prefix on string literals. Windows works almost exclusively with wide strings internally anyway, so the version A-suffixed versions that take narrow string literals are mostly small stubs that convert their arguments to wide strings, then call the wide string version. Using the wide string version directly saves both time and memory.

Narrow string support in Windows was originally there primarily for compatibility with the long-since defunct Windows 95/98/SE/Me line that lacked wide string support. Those have been gone for quite a while, so about the only reason to use narrow literals now is because that's what you're being supplied from some outside source.

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308530

If you continue to use a char * for the parameter, you'll run into cases where an unusual character is used in the filename and the LoadLibrary will fail. Change the function to use wchar_t instead, and while you're at it make the parameter const since you're not modifying the string.

bool PluginLoader::Load(const wchar_t *path)

I think you'll find that LPCTSTR on 32-bit Windows is a macro that expands to const wchar_t * when the program options are set to Unicode.

Upvotes: 0

Oscar Mederos
Oscar Mederos

Reputation: 29863

I suggest you using TCHAR and LoadLibrary instead of using manually char or wchar_t and LoadLibraryA or LoadLibraryW to make a generic application, both for UNICODE and ASCII characters.

So you could do:

TCHAR x[100] = TEXT("some text");

I suggest you reading this article. LPCTSTR is a const TCHAR*.

Why use LoadLibrary instead of LoadLibraryW or LoadLibraryA? To support both UNICODE and ASCII without creating two different programs, one to work with char and the other with wchar_t.

Also, take a look at what Microsoft says about it: Conventions for Function Prototypes

Upvotes: 8

Related Questions