Search code examples
c++windowsloadlibrarystd-filesystem

How can I convert an std::filesystem::path to LPCSTR for use in one of the LoadLibrary() variants?


On Windows I'm trying to use one of the variants of LoadLibrary() to open a dll previously written to an std::filesystem::path with an ofstream.

Note: I know the dll is written correctly as I can use it in the standard fashion by linking to it at runtime.

I've been trying to combine the methods from the two answers below.

How to convert std::string to LPCSTR?

how to convert filesystem path to string

This seems like it should be pretty basic but with anything I've tried so far I either get an error about conversion to LPCSTR or something like C2228: left of '.c_str' must have class/struct/union which I am baffled by.

Here's a simple example:

// Assuming I have 
// std::filesystem::path path1 
// correctly set, I should be able to directly access it in
// a number of ways; i.e. path1.c_str(), path1.string.c_str(), etc.
// in order to pass it the function or a temp variable.
// However direct use of it in LoadLibrary() fails with the C2228 error.

HINSTANCE hGetProcIDDLL = LoadLibrary(path1.c_str());

I've tried avoiding the macro and calling LoadLibraryA() directly with no luck. I've also tried various ways of passing path1 with path1.string(), path1.string.c_str(), path1.wstring(), etc. with no luck. I've also tried using a temp variable in a number of ways to avoid the cast within LoadLibrary().

LPCSTR temp_lpcstr = path1.c_str();  // Also tried things like path1.string() path1.string.c_str()

// Also tried just using a temp string...
std::string temp_string = path1.string(); // and variants.

I'm willing to try playing with the encoding (like path1.u8string() etc.) but I think it shouldn't be necessary with use of LoadLibraryA() directly.

I'm trying to avoid C casts and would prefer a c++ static_ or dynamic_ but I'll use anything that works.

Any help is appreciated.

Thanks in advance.

UPDATE

@eryk-sun's comment and @Gulrak's answer solved it for me. It looks like with my setup, path1.c_str() alone is wchar_t but the LoadLibrary() macro was not picking that up and directing it to LoadLibraryW() as it should.

Note: For anyone else who might stumble onto this in the future here's more details of my specific setup. I'm using the MSVC compiler from 16.1.0 (~VS2019) but that's getting called from VSCode and CMake. I'm not explicitly defining _UNICODE however VSCode's intellisense certainly thinks it's been defined somewhere and points me to LoadLibraryA(). However, I think the compiler is not actually seeing that define so it interprets path1.c_str() as a wchar_t.


Solution

  • Actually on Windows you should be able to use LoadLibraryW(path1.c_str()) as on Windows the returned type of std::filesystem::path::c_str() should be a const wchar_t* so it's a good fit for the LoadLibraryW expected LPCWSTR.

    As for the error of C2228 my guess is, you tried path1.string.c_str() as given by your comment, wich should have been path1.string().c_str(). That would give you a LPCSTR compatible string for LoadLibaryA, but if there is a chance of Non-ASCII in your path I would suggest using the explicit LoadLibaryW version.

    In any way: When interfacing WinAPI with std::filesystem::path you should use the explicit A/W-Version to make your code safe independent of the state of _UNICODE, and I allways suggest the *W versions.