LoadLibrary returning Null - c++

I just tried the following code(windows xp sp3, vs2010) and LoadLibrary seems to be returning Null.
#include "windows.h"
#include "stdio.h"
int main() {
HMODULE hNtdll;
hNtdll = LoadLibrary(LPCWSTR("ntdll.dll"));
printf("%08x\n", hNtdll);
}
The output I get is 00000000. According to the docs, NULL is returned when the function fails. I tried using GetLastError and the error code is 126(0x7e, Error Mod Not Found).
How can I correct this issue?
Thanks!

You have a string literal, which consists of narrow characters. Your LoadLibrary call apparently expects wide characters. Type-casting isn't the way to convert from one to the other. Use the L prefix to get a wide string literal:
LoadLibrary(L"ntdll.dll")
Type-casting tells the compiler that your char const* is really a wchar_t const*, which isn't true. The compiler trusts you and passes the pointer along to LoadLibrary anyway, but when interpreted as a wide string, the thing you passed is nonsense. It doesn't represent the name of any file on your system, so the API correctly reports that it cannot find the module.

You should use LoadLibrary(_T("ntdll.dll")) LPCWSTR just casts char-based string pointer to widestring pointer.

In addition to the necessity of converting the path string to wchar_t const* by using L prefix (which is already mentioned in the accepted answer). According to my last couple of hours experience:
it worths mentioning that LoadLibrary function does not load the dependency(ies) of the intended library (DLL) automatically. In other word, if you try to load the library X which depends on the library Y, you should do LoadLibrary(Y), then LoadLibrary(X), otherwise loading the library X will fail and you will get error 126.

Related

Qt5.9.9+Vs2017 encountered a character set problem [duplicate]

I'm learning to write and use DLLs and this is my first attempt at exporting a function from my dll. It works, but this line is what gave me trouble and what I've been able to find regarding the TEXT cast for UNICODE and ANSI I think I need some guidance. As far as I can find this question has not been asked elsewhere on the site so I apologize if anyone finds what I couldn't.
HINSTANCE hInstLibrary = LoadLibrary("MyDLL.dll");
My initial usage, from a short tutorial on explicit linking gives E0167 and C2664 errors regarding LPCWSTR type
HINSTANCE hInstLibrary = LoadLibrary(TEXT("MyDLL.dll"));
Casting the string to TEXT solves the problem, though I'm not sure why and would like to know
HINSTANCE hInstLibrary = LoadLibraryA("MyDLL.dll");
The line I decided to use in the working example. LoadLibraryA() expands LoadLibrary to accept ANSI rather than Wide, which may be the root of my misunderstanding. Why is this necessary when most examples I find show LoadLibrary("NameOfDLL.dll")?
Why does the string not satisfy the standard LoadLibrary() call?
LoadLibrary() is a preprocessor macro. It maps to either LoadLibraryW() or LoadLibraryA() depending on whether UNICODE is defined or not, respectively. LoadLibraryW() takes a const wchar_t* string as input, while LoadLibraryA() takes a const char * string instead.
The string literal "MyDLL.dll" is a const char[10], which decays into a const char *. If UNICODE is defined, LoadLibrary("MyDLL.dll") will fail to compile, as you cannot pass a const char * where a const wchar_t * is expected.
TEXT() is also a preprocessor macro. If UNICODE is defined, it appends an L prefix to the specified literal making the literal use wchar_t, otherwise no prefix is added and the literal uses char instead.
Thus, if UNICODE is defined, then LoadLibrary(TEXT("MyDLL.dll")) is compiled as LoadLibraryW(L"MyDLL.dll"), otherwise it is compiled as LoadLibraryA("MyDLL.dll") instead.
A majority of Win32 APIs that deal with textual data have similar A and W versions, and corresponding UNICODE-aware preprocessor macros. So, when using character/string literals with these APIs, you should always use the TEXT() macro. Otherwise, just use the A and W APIs directly as needed, depending on the type of textual data you are working with.

Exporting functions from DLLs, LoadLibrary() needs the string cast with TEXT to compile without error

I'm learning to write and use DLLs and this is my first attempt at exporting a function from my dll. It works, but this line is what gave me trouble and what I've been able to find regarding the TEXT cast for UNICODE and ANSI I think I need some guidance. As far as I can find this question has not been asked elsewhere on the site so I apologize if anyone finds what I couldn't.
HINSTANCE hInstLibrary = LoadLibrary("MyDLL.dll");
My initial usage, from a short tutorial on explicit linking gives E0167 and C2664 errors regarding LPCWSTR type
HINSTANCE hInstLibrary = LoadLibrary(TEXT("MyDLL.dll"));
Casting the string to TEXT solves the problem, though I'm not sure why and would like to know
HINSTANCE hInstLibrary = LoadLibraryA("MyDLL.dll");
The line I decided to use in the working example. LoadLibraryA() expands LoadLibrary to accept ANSI rather than Wide, which may be the root of my misunderstanding. Why is this necessary when most examples I find show LoadLibrary("NameOfDLL.dll")?
Why does the string not satisfy the standard LoadLibrary() call?
LoadLibrary() is a preprocessor macro. It maps to either LoadLibraryW() or LoadLibraryA() depending on whether UNICODE is defined or not, respectively. LoadLibraryW() takes a const wchar_t* string as input, while LoadLibraryA() takes a const char * string instead.
The string literal "MyDLL.dll" is a const char[10], which decays into a const char *. If UNICODE is defined, LoadLibrary("MyDLL.dll") will fail to compile, as you cannot pass a const char * where a const wchar_t * is expected.
TEXT() is also a preprocessor macro. If UNICODE is defined, it appends an L prefix to the specified literal making the literal use wchar_t, otherwise no prefix is added and the literal uses char instead.
Thus, if UNICODE is defined, then LoadLibrary(TEXT("MyDLL.dll")) is compiled as LoadLibraryW(L"MyDLL.dll"), otherwise it is compiled as LoadLibraryA("MyDLL.dll") instead.
A majority of Win32 APIs that deal with textual data have similar A and W versions, and corresponding UNICODE-aware preprocessor macros. So, when using character/string literals with these APIs, you should always use the TEXT() macro. Otherwise, just use the A and W APIs directly as needed, depending on the type of textual data you are working with.

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.
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.
You should use string member function of path class which returns std::string. Then call c_stron the returned string.
std::filesystem::path path /* = initialization here */;
std::string str = path.string();
/* some handle = */ LoadLibrary(str.c_str());

Pass BSTR from C++ DLL function to VB6 application

I have this code in my VB6 app:
Private Declare Function FileGetParentFolder Lib "Z-FileIO.dll" _
(ByVal path As String) As String
Output.AddItem FileGetParentFolder(FileText.Text)
Output is a list, FileText is a text field containing a file path. My C++ DLL contains this function:
extern "C" BSTR ZFILEIO_API FileGetParentFolder(Path p)
{
try {
return SysAllocString(boost::filesystem::path(p).parent_path().c_str());
} catch (...) {
return SysAllocString(L"");
}
}
where Path is typedef'd as LPCSTR. The argument comes into my DLL perfectly, but whatever I try to pass back, the VB6 app shows only garbage. I tried several different methods with SysAllocStringByteLength, casting the SysAllocString argument to LPCWSTR and other variants. Either, I only see the first letter of the string, or I see only Y's with dots, just not the real string. Does anyone know what the real method is for creating and passing valid BSTRs from C++ to VB6?
Hopefully this will point you in the right direction. From memory...
VB6 uses COM BSTRs (2-byte wide character strings) internally, but when communicating with external DLLs it uses single- or multi-byte strings. (Probably UTF-8, but I don't remember for sure.) Your Path typedef to LPCSTR is an ANSI string, and that's why you can receive it correctly. The return value you generate is a wide-character string, but VB is expecting an ANSI string. You'll need to use WideCharToMultiByte to convert your return value before returning it.
Seems a little odd that VB does this implicit conversion, but that's the way it is. (As far as I remember.)
If you insist on using the function signature then you have to prepare a custom typelib for VB6 that includes this
[dllname("Z-FileIO.dll")]
module ZFileIO
{
[entry("FileGetParentFolder")]
BSTR FileGetParentFolder ([in] LPWSTR path);
};
In Declares param-types As String are automagically converted to ANSI string, i.e. LPSTR. The only way to pass/receive a unicode string (LPWSTR or BSTR) is by using typelib API function declaration.
Other than that you can always use As Long params in the declaration and expect LPWSTRs but then the consumer will have to wrap strings in StrPtr on every call to the API function.

LoadStringW - winuser.h. What does it do?

I have been unable to find any decent documentation on this function. The code base I am working with uses a function from winuser.h called LoadStringW which takes as arguments: (HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax).
What is this function? What is it for? When might it return 0?
It might be worth a mention that nearly all Win32 APIs that deal with strings have an 'A' and a 'W' variant.
The variant actually called is determined by the definition of macros that don't end in 'A' or 'W' - those macro names are what you might usually think of as the API function's name (LoadString() in this case). UNICODE builds will use the 'W' names and non-UNICODE builds will use the 'A' names.
https://learn.microsoft.com/en-us/windows/desktop/Intl/unicode-in-the-windows-api
There are times when you might want to call a Unicode version of an API even if the build isn't Unicode, in which case you just directly use the name with the 'W' tacked on to the end (it's less often necessary to need to call the non-Unicode APIs in a Unicode build, but it's just as possible). Since the non-Unicode versions of Windows are obsolete, Microsoft has started more and more to implement only Unicode versions of APIs. Note that in nearly all cases, all that the non-Unicode versions of the APIs do is to convert the ANSI/MBCS strings to Unicode, call the 'W' function, then clean up afterward.
LoadStringW is the Unicode version of LoadString.
The documentation states "If the function succeeds, the return value is the number of TCHARs copied into the buffer, not including the terminating NULL character, or zero if the string resource does not exist. To get extended error information, call GetLastError."
Here is the documentation for LoadString(): http://msdn.microsoft.com/en-us/library/ms647486%28VS.85%29.aspx
.. and here is the documentation explaining the differences between ANSI and Unicode functions in the Windows API: http://msdn.microsoft.com/en-us/library/cc500321.aspx.
Basically, the function LoadString comes in two flavours, ANSI and Unicode. LoadStringW is the Unicode-specific version of LoadString.
Edit: Just to be clear, there aren't really two completely separate functions. The ANSI version really just converts the string and calls the unicode version, which does all of the real work.
LoadStringW() is the WideCharacter version of the LoadString function.
See MSDN
It loads a widestring from a stringtable resource using the Windows Unicode Layer for Win95 and NT 3.51. See MSDN for details (see the remarks section).
For the umpteenth time, I just confirmed that when the resource compiler is instructed to null terminate the strings, the count returned by LoadString includes the terminal NULL character. I did so by examining the output buffer that I made available to LoadString.
Resource strings are not null terminated by default. In that case, the returned count excludes the terminal null character, as described in the documentation, because the null is appended by the function after the string is copied into the output buffer.
I suspect this behavior is due to the fact that LoadString disregards the fact that the resource compiler was instructed to null terminate the strings. Indeed, I suspect that it has no way of knowing that they were.
With respect to why you would want to null terminate your resource strings in the first place, when they work just fine without them, and your PE file is thereby a tad smaller, the reason is that the wide character implementation of LoadString, at the LoadStringW entry point, returns a pointer to the string, rather than copying it into a buffer, if the buffer address passed into it is a NULL pointer. Unless your strings are null terminated, using LoadString in this way produces quite unwelcome results.
Since resource strings are always stored as Unicode (wide character) strings, the ANSI implementation of LoadString cannot return a pointer, as the string must be converted to ANSI; hence, it cannot simply be copied.