Closed rohybnol closed 3 years ago
2 solutions:
LI_FN_DEF
:
// definition copied from the headers and turned into a function pointer
using D2D1CreateFactory = HRESULT(WINAPI*)(D2D1_FACTORY_TYPE, REFIID, CONST D2D1_FACTORY_OPTIONS*, void**);
// this will now work
LI_FN_DEF(D2D1CreateFactory)(...);
#define D2D_USE_C_DEFINITIONS
which will get rid of C++ overloads, but might potentially break your code / libraries you plan to also include that actually use those overloads.If those overloads were actually functional and weren't just a wrapper for the C API, you'd be in a world of pain, as the library would need the mangled name, but thankfully that's not the case.
Method 1 results into error C2365: "D2D1CreateFactory": redefinition; previous definition was "function".
Method 1 results into error C2365: "D2D1CreateFactory": redefinition; previous definition was "function".
#include <Windows.h>
#include <d2d1.h>
#include "lazy_importer.hpp"
int main() {
LoadLibraryA("d2d1.dll");
using D2D1CreateFactory =
HRESULT(WINAPI*)(
_In_ D2D1_FACTORY_TYPE factoryType,
_In_ REFIID riid,
_In_opt_ CONST D2D1_FACTORY_OPTIONS* pFactoryOptions,
_Out_ void** ppIFactory
);
void* pFactory;
LI_FN_DEF(D2D1CreateFactory)(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), nullptr, &pFactory);
}
This compiles and runs perfectly fine for me.
Following exactly your example, however overhere there seem to be an issue, I am not really able to figure it out on my own whats happening.
using D2D1CreateFactory =
HRESULT(WINAPI*)(
_In_ D2D1_FACTORY_TYPE factoryType,
_In_ CONST D2D1_FACTORY_OPTIONS& factoryOptions,
_Out_ void** ppFactory
);
LI_FN_DEF(D2D1CreateFactory)(D2D1_FLAGS, FactoryOptions, &d2d_factoryPtr);
Compiler output:
LazyImports.hpp(534,48): error C2664: "HRESULT (D2D1_FACTORY_TYPE,const D2D1_FACTORY_OPTIONS &,void **)" : conversion of argument 3 from "_Ty" to "void **" not possible
1> with
1> [
1> _Ty=ID2D1Factory2 **
1> ]
LazyImports.hpp(532,1): error C3169: "decltype(auto)": cannot derive type for "auto" from "HRESULT
Main.cpp(100,1): error C3779: "li::detail::lazy_function<1634981206,D2D1CreateFactory>::operator ()": a function that returns "decltype(auto)" must not be used before it is defined.```
&d2d_factoryPtr
is ID2D1Factory2 **
which cannot be converted to void **
- you'd simply need to explicitly cast the pointer (reinterpret_cast
or C style cast in this case).
⚠️ IMPORTANT: I think you copied the C++ function definition and not the C definition. This wont work. There is only a single exported variant of this function and that is the C version with 4 parameters.
// this is just a wrapper from windows headers that I am assuming you copied - you want to use the real function that it's calling
template<class Factory>
COM_DECLSPEC_NOTHROW
HRESULT
D2D1CreateFactory(
_In_ D2D1_FACTORY_TYPE factoryType,
_In_ CONST D2D1_FACTORY_OPTIONS &factoryOptions,
_Out_ Factory **ppFactory
)
{
return
D2D1CreateFactory(
factoryType,
__uuidof(Factory), // <- the extra parameter that you need to have
&factoryOptions,
reinterpret_cast<void **>(ppFactory)); // <- the cast that you were missing
}
This is what your code should look like I think.
using D2D1CreateFactory =
HRESULT(WINAPI*)(
_In_ D2D1_FACTORY_TYPE factoryType,
_In_ REFIID riid,
_In_opt_ CONST D2D1_FACTORY_OPTIONS* pFactoryOptions,
_Out_ void** ppIFactory
);
LI_FN_DEF(D2D1CreateFactory)(D2D1_FLAGS, __uuidof(ID2D1Factory2), FactoryOptions, (void**)&d2d_factoryPtr);
You was right I've got that solved now. I have spot another issue as well when trying to use DefWindowProc like that:
LRESULT CALLBACK winproc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
{
return LI_FN(DefWindowProcW)(hwnd, wm, wp, lp);
}
user32.dll is already loaded so thats not the issue, test env. just crashes when calling it.
thank you very much, great lib btw!
thank you very much, great lib btw!
Thanks
I have spot another issue as well when trying to use DefWindowProc like that:
It's a forwarded export. The handling of them is explicit in this library.
LAZY_IMPORTER_CASE_INSENSITIVE
. This is technically not mandatory but pretty much all forwarded exports will have the dll name in wrong case, so it's rather unlikely to work without this.LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS
, so most functions will try to resolve forwarded exports by default..forwarded()
member function that returns the pointer, instead of the operator()
overload. IE. LI_FN(DefWindowProcW).forwarded()(...)
As a small side note, you might want to cache the pointers to functions that will continuously be called. Either by your own mechanism or just using the built in functionality (take a look at the table in the readme), as these lookups aren't exactly free.
Alright I fully understand it now, thanks for explaining everything detailed like that - I got it all solved now with your instructions. By any chance, do you know a good way to get rid of all other imports like CRT as well? thanks again this lib is really great and you are a great person too, have a good one!
By any chance, do you know a good way to get rid of all other imports like CRT as well?
Well it depends on what features you want to use. Getting STL work without exceptions enabled doesn't take too long (maybe a few hundred lines of copy pasting from google). But essentially you just don't link with CRT -> /nodefaultlib
in linker options (it's called ignore default libraries or something like that) and then just implement missing functions as you go.
have a good one
You too 👍
Using this
LI_FN(D2D1CreateFactory)(D2D1_FLAGS, FactoryOptions, &d2d_factoryPtr);
leads me to this compiler output: C++ Unable to determine which instance of D2D1CreateFactory is intended. The Direct2D system library provides 4 overloaded versions for the D2D1CreateFactory function, how can I choose the right one for the LI_FN macro? Thanks