c# PInvoke w_char_t** - interop

I have the following c++ function which I cannot alter (3rd-Party):
[c++]
int __stdcall TEST(wchar_t **xml, int &result_size)
{
// xml is instantiated here!
}
[c#]
class native
{
[DllImport("somedll.dll")]
public static extern int TEST(StringBuilder a, ref int size);
{
}
}
Example:
StringBuilder b = new StringBuilder();
int size = 0;
native.Test(b,ref size)
The stringbuilder object only contains first character . If I resize the object:
b.Length = size; The data is incorrect except first character.
Is this the correct way to pass wchar_t** from c++ to c#?
Regards,
John

The function would be p/invoked like this:
[DllImport(#"mylib.dll")]
static extern int TEST(out IntPtr xml);
I removed the size paramter since it is not needed since you can use a null-terminated string.
Call the function like this:
IntPtr xmlptr;
int retval = TEST(out xmlptr);
string xml = Marshal.PtrToStringUni(xmlptr);
// deallocate xmlptr somehow
The tricky bit is to deallocate the memory allocated on the native side. Either use a shared allocator, e.g. the COM allocator. Or export a deallocator from the native code.
Personally I'd re-design the interface to use COM BSTR. I'd have the C++ return a BSTR and on the managed side use [MarshalAs(UnmanagedType.BStr)]. Then the framework handles all the deallocation and marshalling for you.

Related

GetFinalPathNameByHandle fails for device handles

If I create a File handle using CreateFile for a path like "\\?\NUL" or "\\?\pipe\", the handle is mapped to a File object that's opened for the "\Device\Null" or "\Device\NamedPipe" kernel Device object. Since the GetFinalPathNameByHandle function supports the VOLUME_NAME_NT property, which already returns strings like "\Device\HarddiskVolume1\", I thought I would be able to obtain a similar path for a device handle. However, the call always fails, either with ERROR_INVALID_FUNCTION, or ERROR_INVALID_PARAMETER, depending on the access flags the file was opened with.
In fact, almost any call to similar functions fails -- like GetFileInformationByHandle, GetFileInformationByHandleEx, and even calls to NT functions like NtQueryInformationFile -- returning STATUS_INVALID_PARAMETER. The only functions that don't fail are GetFileType (able to identify a pipe), GetVolumeInformationByHandle (able to identify the driver), and NtQueryInformationFile with FileModeInformation.
All these functions work when used on any standard file, but they are not supported for device file handles. How can I obtain path information from a device handle? Are there some Nt or Io functions that would work? Is there some other way to identify a device if the only thing I have is the handle?
As RbMm and eryksun have pointed out, the driver which implements the object must be able to handle IRP_MJ_QUERY_INFORMATION, but if it doesn't, the name of the object can be obtained via NtQueryObject, passing ObjectNameInformation (1) to it, which will obtain the OBJECT_NAME_INFORMATION structure with the object name.
Since I intended to call it with C#, here is the P/Invoke code for it:
static class Ntdll
{
[DllImport("ntdll.dll")]
static extern int NtQueryObject(
IntPtr Handle, int ObjectInformationClass,
IntPtr ObjectInformation, int ObjectInformationLength,
out int ReturnLength
);
public static int NtQueryObject(IntPtr Handle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength)
{
int length;
int status = NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, out length);
if(status != 0) throw new Win32Exception(RtlNtStatusToDosError(status));
return length;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct OBJECT_NAME_INFORMATION
{
public ushort Length;
public ushort MaximumLength;
public string Buffer;
}
[DebuggerStepThrough]
public static void NtQueryObject(IntPtr Handle, out OBJECT_NAME_INFORMATION ObjectNameInformation)
{
IntPtr buffer = Marshal.AllocHGlobal(1024);
try{
Ntdll.NtQueryObject(Handle, 1, buffer, 1024);
ObjectNameInformation = Marshal.PtrToStructure<Ntdll.OBJECT_NAME_INFORMATION>(buffer);
}finally{
Marshal.FreeHGlobal(buffer);
}
}
}
The path can be then constructed by prepending "\\?\GlobalRoot" to the Buffer member.

std::shared_ptr and dlopen(), avoiding undefined behavior

dlopen() is a C function used for dynamically loading shared libraries at runtime. The pattern, in case you're not familiar, is thus:
Call dlopen("libpath", flag) to get a void *handle to the library
Call dlsym(handle, "object_name") to get a void *object to the thing you want from the library
Do what you want with object
Call dlclose (handle) to unload the library.
This is, in C++, a perfect use-case for the so-called aliasing constructor of std::shared_ptr. The pattern becomes:
Construct a std::shared_ptr<void> handle from dlopen("libpath", flag) that will call dlclose() when its destructor is called
Construct a std::shared_ptr<void> object from handle and dlsym(handle, "object_name")
Now we can pass object wherever we want, and completely forget about handle; when object's destructor is called, whenever that happens to be, dlclose() will be called automagically
Brilliant pattern, and it works beautifully. One small problem, though. The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
In C, there is a hack to get around this. From the dlopen man page:
// ...
void *handle;
double (*cosine)(double);
// ...
handle = dlopen("libm.so", RTLD_LAZY);
// ...
/* Writing: cosine = double (*)(double)) dlsym(handle, "cos");
would seem more natural, but the C99 standard leaves
casting from "void *" to a function pointer undefined.
The assignment used below is the POSIX.1-2003 (Technical
Corrigendum 1) workaround; see the Rationale for the
POSIX specification of dlsym(). */
*(void **) (&cosine) = dlsym(handle, "cos");
// ...
which obviously works just fine, in C. But is there an easy way to do this with std::shared_ptr?
The pattern above requires a cast from void* to whatever_type_object_is*. If "object_name" refers to a function (which most of the time it does, considering the use-case), this is undefined behavior.
Well this is not entirely true, at least in C++ it is just conditionally-supported.
5.2.10.8 says:
Converting a function pointer to an object pointer type or vice versa is conditionally-supported. The meaning
of such a conversion is implementation-defined, except that if an implementation supports conversions in
both directions, converting a prvalue of one type to the other type and back, possibly with different cvqualification,
shall yield the original pointer value.
So assuming that what dlsym does internally is casting a function pointer to a void*, I believe that you are ok if you just cast it back to a function pointer.
Something like this?
struct dlib
{
public:
template<class T>
std::shared_ptr<T> sym(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
return {reinterpret_cast<T*>(sym), handle};
}
// returns a smart pointer pointing at a function for name:
template<class Sig>
std::shared_ptr<Sig*> pfunc(const char* name) const {
if (!handle) return {};
void* sym = dlsym(handle->get(), name);
if (!sym) return {};
Sig* ret = 0;
// apparently approved hack to convert void* to function pointer
// in some silly compilers:
*reinterpret_cast<void**>(&ret) = sym;
return {ret, handle};
}
// returns a std::function<Sig> for a name:
template<class Sig>
std::function<Sig> function(const char* name) const {
// shared pointer to a function pointer:
auto pf = pfunc(name);
if (!pf) return {};
return [pf=std::move(pf)](auto&&...args)->decltype(auto){
return (*pf)(decltype(args)(args)...);
};
}
dlib() = default;
dlib(dlib const&)=default;
dlib(dlib &&)=default;
dlib& operator=(dlib const&)=default;
dlib& operator=(dlib &&)=default;
dlib(const char* name, int flag) {
void* h = dlopen(name, flag);
if (h)
{
// set handle to cleanup the dlopen:
handle=std::shared_ptr<void>(
h,
[](void* handle){
int r = dlclose(handle);
ASSERT(r==0);
}
);
}
}
explicit operator bool() const { return (bool)handle; }
private:
std::shared_ptr<void> handle;
};
I doubt that hack is needed. As #sbabbi noted, the round-trip to void* is conditionally supported. On a system using dlsym to return function pointers, it better be supported.
You can make a struct to have your pointer to function and handle to library:
template<typename T>
struct dlsymbol {
dlsymbol( const std::string &name, std::shared_ptr<void> handle ) :
m_handle( std::move( handle ) )
{
*(void **)(&m_func) = dlsym( handle.get(), name.c_str );
}
std::shared_ptr<void> m_handle;
T *m_func;
};
auto cosine = std::make_shared<dlsymbol<double(double)>>( "cos", handle );
auto d = cosine->m_func( 1.0 );
I did not compile it, but I think it is sufficient to show the idea.

shared_ptr and COM object

I have a COM object named factory (IFactory), and it has several methods like
virtual HRESULT STDMETHODCALLTYPE CreateDatabase(IDatabase** Result) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateProcessor(IProcessor** Result) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateDocument(IDocument** Result) = 0;
.....
when I need create a IDocument, I need to do this:
IDocument* doc = nullptr;
factory->CreateDocument(&doc);
// some code here;
doc.Release();
So I want to create a common function to do this and generate a shared_ptr, so taht I do not need to release it manually.
I created a function like this:
template <typename T, typename K>
shared_ptr<T> create_new(K* p, HRESULT (K::*member)(T**)) {
T* pointer = nullptr;
(void)p->*member(&pointer);
shared_ptr<T> result(pointer, [=](T* o) {
o->Release();
});
return result;
}
This way, when I need create a new IDocument I just need:
auto doc = create_new(factory, &IFactory::CreateDocument);
// do not need release it manually
but this does not work, because the compiler needs more information to instantiate the template, so I use
auto doc = create_new(factory, (HRESULT (IFactory::*)(IDocument**))&IFactory::CreateDocument);
this way seems correct, but when I compile my code, the compiler stops at
(void)p->*member(&pointer);
and says:
must use '.*' or '->*' to call pointer-to-member function in 'member (...)', e.g. '(... ->* member) (...)'
In instantiation of 'std::shared_ptr<_Tp1> create_new(K*, HRESULT (K::*)(T**)) [with T = IDocument; K = IFactory; HRESULT = long int]'
Could someone help me figure this out?
Compiler is MinGW-w64 GCC 4.8.5, but I tried GCC 5.3.0, with the same output.
First off, function calls bind tighter than member pointer dereference, so you need these parentheses:
(p->*member)(&pointer);
(Add cast to void as you prefer).
Second, you can improve your call syntax by specifying the argument for T explicitly; you should then not need the horrible cast:
auto doc = create_new<IDocument>(factory, &IFactory::CreateDocument);

C# DllImport issue calling C++ library

I need to call a C++ library from a C# program, I have a method whose signature looks like:
int __stdcall meythodName(const char *c, struct TheirStruct[] s1, struct TheirStruct[] s2)
all parameters are output parameters.
I'm trying to call this method like this:
[DllImport("theirlib.dll", CallingConvention = CallingConvention.StdCall)]
extern static int meythodName(ref string c, ref TheirStruct[] s1, ref TheirStruct[] s2);
With TheirStruct being like:
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = 13)]
public class TheirStruct
{
public int i;
public int j;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
public string s;
}
TheirStruct (PACKED and 13 byte in size) is described in dll manual as:
#define LEN 5
#define SIZE 50
struct TheirStruct
{
char c[LEN];
int i;
int j;
};
When I try to call this method my application simply terminates without giving me an error code, can you give me some explanations about this issue?
Found!!!
I just needed to change "class" to "struct" in TheirStruct declaration, remove di "ref" keyword in method invocation and set the [In]/[Out] accordingly.
Quite simple, hope this can be of any help!!

Can I hook functions in linked libraries?

Using EasyHook I have successfully hooked both exported functions and known vtable functions for various C++ classes. In all these cases target programs have used DLLs.
Provided I know the address of a function's entry point, is it possible to do the same when a library has been linked into the target program as opposed to being a separate library?
It appears with EasyHook you can hook any subroutine whose address is calculable.
In my case hooking static linked SSL_read and SSL_write in OpenSSL was as simple as identifying the offsets with my favourite debugger and then installing the hooks.
// delegate for EasyHook:
[UnmanagedFunctionPointer(CallingConvention.Cdecl,
SetLastError = true, CharSet = CharSet.Ansi)]
delegate Int32 SLL_readDelegate(IntPtr SSL_ptr, IntPtr buffer, Int32 length);
// import SSL_read (I actually did it manually, but this will work in most cases)
/* proto from ssl_lib.c -> int SSL_read(SSL *s,void *buf,int num) */
[DllImport("ssleay32.dll", SetLastError = true)]
public static extern Int32 SSL_read(IntPtr ssl, IntPtr buffer, Int32 len);
// the new routine
static Int32 SSL_readCallback(IntPtr SSL_ptr, IntPtr buffer, Int32 length)
{
/* call the imported SSL_read */
int ret = SSL_read(SSL_ptr, buffer, length);
/* TODO: your code here, e.g:
* string log_me = Marshal.PtrToString(buffer, ret);
*/
return ret;
}
Now all that's left is to install the hook:
private LocalHook sslReadHook;
public void Run(RemoteHooking.IContext InContext, String InArg1)
{
// ... initialization code omitted for brevity
/* the value for ssl_read_addr is made up in this example
* you'll need to study your target and how it's loaded(?) to
* identify the addresses you want to hook
*/
int ssl_read_addr = 0x12345678; /* made up for examples sake */
sslReadHook = LocalHook.Create(new IntPtr(ssl_read_addr),
new SSL_readDelegate(SSL_readCallback), this);
// ...
}
I should mention that in this example you'll need libeay32.dll and ssleay32.dll as the latter depends on the former.
Happy hooking!

Resources