I have to dynamically load the DLL interface of libxml2 via LoadLibrary and GetProcAddress under Windows. All of the function pointers I've used are properly loaded, except for xmlFree.
xmlFree is not a normal DLL export, but instead a function pointer. GetProcAddress on "xmlFree" will thus return a pointer to a pointer to the xmlFree function.
typedef void (*LibXmlFree) (void* mem);
LibXmlFree xmlFree = GetProcAddress( hModule, "xmlFree" );
This will thus succeed, but calling this function will fail because xmlFree doesn't point to the real function.
How do I create a proper pointer to DLL's xmlFree(void*) export?
To assign the real xmlFree pointer you have to dereference the pointer returned by GetProcAddress.
The first part of the cast specifies the result type, the second part dereferences it with the proper type specification.
xmlFree = (void (__cdecl *)(void *)) *((void (__cdecl **)(void *)) GetProcAddress( hModule, "xmlFree" ));
Same should apply to libxml's other function pointers (malloc, realloc & friends).
There is a funciton to obtain an address xmlFree:
xmlGlobalState xmlMem = {};
xmlMemGet( &xmlMem.xmlFree,
&xmlMem.xmlMalloc,
&xmlMem.xmlRealloc,
&xmlMem.xmlMemStrdup
);
xmlMem.xmlFree( result );
I had similar problem with xmlFree being NULL, while compiling under mingw.
Effectively xmlFree() failed with SIGSEGV.
Related
I'm a little bit confused with GetProcAddress().
Quoting the Win32 docs:
If the function succeeds, the return value is the address of the exported function or variable.
I know that for functions, GetProcAddress() returns a function pointer that calls the desired function. However, it isn't clear what GetProcAddress() returns in something like this:
DLL code
typedef struct {
uint64_t foo;
double bar;
char* baz;
} MyStruct;
__declspec(dllexport) MyStruct* my_struct_ptr;
__declspec(dllexport) long long special_global;
Application code
void* my_struct_ptr = GetProcAddress(my_dll_handle, "my_struct_ptr");
void* special_global = GetProcAddress(my_dll_handle, "special_global");
What would my_struct_ptr and special_global in the application point to?
EDIT: Does my_struct_ptr point to the DLL's my_struct_ptr or the struct that the DLL's my_struct_ptr points to?
I am working with shared_ptr storing pointers of a C library.
Here an example of such a C library containing the header bar.h:
#pragma once
typedef struct Flupp MyFlupp;
MyFlupp *
create_flupp();
void
del_flupp(MyFlupp * fp);
void
print_flupp(MyFlupp * f);
Here the struct has a forward declaration and is defined in the bar.so.
I am using the bar.so in my C++ code:
#include <memory>
extern "C"{
#include "bar.h"
}
int main()
{
std::shared_ptr<MyFlupp> flupp_ptr(nullptr, del_flupp);
flupp_ptr.reset(create_flupp());
print_flupp(flupp_ptr.get());
return 0;
}
Here I am storing the MyFlupp* in a shared_ptr. On the declaration, MyFlupp* is unknown and set to nullptr. Later I am calling the reset operation to set the valid pointer. But when I am compling the code, I get the following error:
In file included from /usr/include/c++/8/bits/shared_ptr.h:52,
from /usr/include/c++/8/memory:81,
from test_foo.cpp:1:
/usr/include/c++/8/bits/shared_ptr_base.h: In instantiation of ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Yp*) [with _Yp = Flupp; <template-parameter-2-2> = void; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2]’:
/usr/include/c++/8/bits/shared_ptr_base.h:1293:4: required from ‘std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> std::__shared_ptr<_Tp, _Lp>::reset(_Yp*) [with _Yp = Flupp; _Tp = Flupp; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2; std::__shared_ptr<_Tp, _Lp>::_SafeConv<_Yp> = void]’
test_foo.cpp:10:35: required from here
/usr/include/c++/8/bits/shared_ptr_base.h:1126:19: error: invalid application of ‘sizeof’ to incomplete type ‘Flupp’
static_assert( sizeof(_Yp) > 0, "incomplete type" );
When I am providing the deleter to the reset operation than it is working.
flupp_ptr.reset(create_flupp(), del_flupp);
Can anybody explain me whats going on? I already looked #cppreference but I does not found an answer.
The problem is that the type Flupp has only been forward-declared, but not defined. In the context of the use here, it is considered an incomplete type.
This has certain implications for the use with std::shared_ptr:
std::shared_ptr may be used with an incomplete type T. However, the
constructor from a raw pointer (template<class Y> shared_ptr(Y*)) and
the template<class Y> void reset(Y*) member function may only be
called with a pointer to a complete type (note that std::unique_ptr
may be constructed from a raw pointer to an incomplete type).
Source: cppreference.com
Instead you need to use the respective overloads that accept a pointer and the deleter as arguments.
With unique_ptr this is not necessary, as that one stores the custom deleter as part of the type. But with shared_ptr the deleter is type-erased and only recovered at runtime. This allows you to change the deleter of an existing shared_ptr when calling reset. For this reason you always need to re-state which deleter to use whenever you're calling reset. If no deleter is given, each call to reset will also implicitly reset the deleter to just calling delete on the managed pointer.
So to make it work, just change your reset call to
flupp_ptr.reset(create_flupp(), del_flupp);
Is there a technical reason why std::exchange does not work on std::vector::reference or is it a bug in the implementation of GCC and Clang? With MSVC it compiles fine.
I have a setup like this (minimal example)
struct Manager
{
std::vector<bool> lifeTimes;
//Should return the state before trying to kill it
bool kill(std::size_t index)
{
return std::exchange(lifeTimes[index], false);
}
};
std::exchange would make this a really nice one liner but GCC complains about:
error: cannot bind non-const lvalue reference of type ‘std::_Bit_reference&’ to an rvalue of type ‘std::vector::reference’ {aka ‘std::_Bit_reference’}
So it seams it complains about the false since only the second parameter is an rvalue
It is not a bug, MSVC compiles your code because it has an extension which enables binding temporary object (Rvalue) to non-const Lvalue reference.
Below code compiles with MSVC:
void foo(int& i) {}
foo(20); // you are passing Rvalue and it is bound to Lvalue reference
Above code doesn't compile under G++ or CLang, when you add const to make reference to
const Lvalue, it works:
void foo(const int&){}
foo(20); // you can bind Rvalue to const Lvalue reference
A few words about vector. operator[] for vector<T> where T is every type except bool returns T&:
T& vector<T>::operator[](index) // where T is not bool
For bool vector class template has specialization. Values of bool are stored to hold one bit space, because you cannot use address-of operator for one bit, vector<bool>::operator[](index) cannot return reference. vector<bool> has inner proxy class which manipulates bits (call this class as reference).
vector<bool>::reference vector<bool>::operator[](index)
^^^^^^^^^
as you see object of proxy is passed by value.
So when you call
return std::exchange(lifeTimes[index], false);
you are passing temporary objecy (Rvalue) to exchange which takes first argument by reference to non-const Lvalue. This is the cause that G++ discards this code. If you want to compile it you can explicitly create Lvalue object of proxy class and pass it:
bool kill(std::size_t index)
{
std::vector<bool>::reference proxyForBit = lifeTimes[index];
return std::exchange(proxyForBit, false);
}
In trying to create an IWIC Factory, the CoCreateInstance function is returning E_INVALIDARG (One or more arguments are invalid). I checked MSDN and I cannot see which of these arguments could be invalid.
IWICImagingFactory* iwicfactory = nullptr;
HRESULT IWFactHRes = CoCreateInstance(CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
(LPVOID*)iwicfactory
);
Am I missing something?
The final parameter to CoCreateInstance is the
address of pointer variable that receives the interface pointer requested in riid.
Your code currently passes the pointer variable, not the address of it. You have to change
(LPVOID*)iwicfactory
to
(LPVOID*)&iwicfactory
Additional notes:
It is a good idea to use the IID_PPV_ARGS macro, which ensures that IID and interface pointer are in sync as well as removing the need for a cast:
HRESULT IWFactHRes = CoCreateInstance(CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&iwicfactory)
);
COM needs to be initialized on the calling thread before the call to CoCreateInstance. Call either CoInitialize or CoInitializeEx to do so.
I'm trying to create a thin wrapper of Windows MMDevice API for Go, and I faced the problem about Windows data types for strings.
According to the documentation of IMMDevice::GetId method, it takes the parameter below:
HRESULT GetId(
[out] LPWSTR *ppstrId
);
And here is my Go code that corresponds to the method above. (github.com/moutend/ywca/immdevice_windows.go:13)
func getId(mmd *IMMDevice, strId *uint16) (err error) {
hr, _, _ := syscall.Syscall(
mmd.VTable().GetId,
2,
uintptr(unsafe.Pointer(mmd)),
uintptr(unsafe.Pointer(strId)),
0)
// ...
}
My understand is that the LPWSTR is the pointer to the array of uint16 values, but it causes invalid pointer error.
What type should I use in this case? Thanks.
It is a pointer to a pointer. The LPWSTR type is a wchar_t* and therefor the parameter in that method is a wchar_t**.
You are not passing in a string buffer for the method to fill. The method will allocate memory with CoTaskMemAlloc and return this memory address back to you after it has been filled. You are responsible for freeing this memory with CoTaskMemAlloc.
The first thing to do is read the documentation for the Windows function.
IMMDevice::GetId
method,
HRESULT GetId(
[out] LPWSTR *ppstrId
);
Parameters
ppstrId [out]
Pointer to a pointer variable into which the method writes the address
of a null-terminated, wide-character string containing the endpoint
device ID. The method allocates the storage for the string. The caller
is responsible for freeing the storage, when it is no longer needed,
by calling the CoTaskMemFree function. If the GetId call fails,
*ppstrId is NULL. For information about CoTaskMemFree, see the Windows SDK documentation.
Return value
If the method succeeds, it returns S_OK. If it fails, possible return
codes include, but are not limited to, the values shown in the
following table.
In particular, "ppstrId [out] Pointer to a pointer variable ..." You have strId *uint16 or *pstrId when I would expect you to have strId **uint16 or *ppstrId.