C++/CLI marshaling delegate with string argument to wchar_t* - c++

I am trying to marshal a callback function in C++/CLI. The following example only prints an "H" so the marshaling of the wide chars to the managed string doesn't seem to work even though I have specified [MarshalAs(UnmanagedType::LPWStr)].
Also tried marshaling using BSTRs but got the same result.
typedef void(*PFN_PRINT)(const wchar_t*);
void PrintHej(PFN_PRINT pfnPrint)
{
pfnPrint(L"Hej");
}
ref class PrinterClass
{
public:
static void Printer(String^ str)
{
Console::WriteLine(str);
}
};
delegate void PrinterDelegate([MarshalAs(UnmanagedType::LPWStr)] String^);
int main(array<System::String ^> ^args)
{
PrinterDelegate^ pDelegate = gcnew PrinterDelegate(&PrinterClass::Printer);
GCHandle gch = GCHandle::Alloc(pDelegate);
IntPtr pFn = Marshal::GetFunctionPointerForDelegate(pDelegate);
PrintHej(static_cast<PFN_PRINT>(pFn.ToPointer()));
gch.Free();
return 0;
}

Related

Getting Read/Write access error when trying to use method from external library

I am trying to use the following implementation from a library
C++
int CALLBACK xCallback(long xmitlen, int buflen, char *buf, long flen)
{
return 0;
}
extern "C" __declspec(dllexport) int __stdcall TXFIlestransfer(int port, string fileName);
__declspec(dllexport) int __stdcall TXFIlestransfer(int port, string fileName)
{
int ret;
char *test = &fileName[0];
ret = sio_FtKermitTx(port, test, xCallback, 27);
return ret;
}
I am importing this to use with C# and am getting System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
Any help with resolving this error would be greatly appreciated.
I tested your program by simulating the sio_FtKermitTx function in my C++ dll (Mydll.dll):
int sio_FtKermitTx (int port, char *fname, int (CALLBACK *func) (long xmitlen, int buflen, char *buf, long flen), int key)
{
return 5;
}
And even with an empty body, I have the same problem as you.
After several investigations, I noticed that the problem came from the fact that we are using a string object between C# and C++ code which for one reason or another (unicode / multibyte configuration for example, or simply because sharing complex objects is difficult to implement) causes problem.
Solution:
By replacing the string object with a primitive char type, everything works correctly:
C# Code:
using System.Runtime.InteropServices;
namespace MyProgramme
{
class Test
{
// Import C++ DLL
[DllImport("Mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TXFIlestransfer(int i, char[] filename);
//public static extern int TXFIlestransfer(int i, string filename); // this crash
static void RunTest(/*LoadFilterEVENTMessage msg*/)
{
string c = "ABC";
char[] char_arr = c.ToCharArray();
int i = TXFIlestransfer(3, char_arr);
// int i = TXFIlestransfer(3, c); string version crash
string s = i.ToString();
MessageBox.Show(s);
}
/* Methods in DLL being used below */
public static void Main()
{
RunTest();
}
};
}
C++ DLL code (Mydll.dll) :
extern "C" __declspec(dllexport) int TXFIlestransfer(int port, char fileName[])
{
int ret;
char *test = &fileName[0];
ret = sio_FtKermitTx(port, test, xCallback, 27);
return ret;
}
anyway, your sio_FtKermitTx function accepts a char* in parameter, so changing your TXFIlestransfer parameters from string to char[] is not problematic.
Result:
After running C# program you will get this:

When using "new" to initialize unique_ptr<FILE*,File::Close> is the custom deleter responsible for freeing that memory?

Smart Pointers are a new concept for me. I have been trying to wrap a File class around fopen_s and fclose using a smart pointer with a custom deleter (unique_ptr).
Below is my attempt. It successfully compiles, runs, and generates a file named "text.txt" with the contents "Hello World" as expected.
I had to use "new" to initialize unique_ptr in my Open function since make_unique does not appear work with custom deleters. Since I am using "new" is my custom deleter responsible for freeing that allocated memory?
I have stepped through my program (VS2019). File::Close only gets called once. I expected it to be called when "handle" in my File:Open function went out of scope, but this was not the case. This behavior may be influenced by the call to std::move(). Not sure how to investigate further on what happens here.
#include <Windows.h>
#include <memory>
#include <string>
#include <map>
class File
{
private:
//functors - custom deleter
struct Close { void operator()(FILE** _handle); };
//type definitions
typedef std::unique_ptr<FILE*,File::Close> Handle;
typedef std::map<std::string,Handle> HandleMap;
//static members
static Handle& Open(std::string _name, std::string _mode);
static HandleMap s_handle_map_;
//variables
Handle& handle_;
std::string name_;
public:
//functions
File(std::string _name, std::string _mode);
void Write(std::string _message);
};
File::HandleMap File::s_handle_map_;
File::File(std::string _name, std::string _mode)
:handle_(Open(_name,_mode)),
name_(_name)
{
}
File::Handle& File::Open(std::string _name, std::string _mode)
{
bool exist = s_handle_map_.count(_name) > 0;
if (!exist)
{
Handle handle(new FILE*(nullptr));
//open new file
fopen_s(
handle.get(),
_name.c_str(),
_mode.c_str()
);
//transfer ownership of handle
s_handle_map_.emplace(
_name,
std::move(handle)
);
}
return s_handle_map_[_name];
}
void File::Close::operator()(FILE** _handle)
{
fclose(*_handle);
*_handle = nullptr;
//necessary?
delete _handle;
_handle = nullptr;
}
void File::Write(std::string _message)
{
fprintf(*handle_, _message.c_str());
}
int WINAPI WinMain(HINSTANCE _instance, HINSTANCE _previous, LPSTR _cmd, int _show)
{
File file("test.txt","w");
file.Write("Hello World\n");
return 0;
}
Whenever you think of unique_ptr<FILE*, ...>, take a deep breath in, wait a minute, then go on with fstream.
The following code does the same thing, but relies on a proven and well tested C++ standard library. fstream have all the features you expect, including automated closing when they are no longer needed:
int WINAPI WinMain(HINSTANCE _instance, HINSTANCE _previous, LPSTR _cmd, int _show)
{
fstream file("test.txt", fstream::out);
file << "Hello World\n";
return 0;
}
And you do not need to worry about memory management at all.
Now, generalizing your question :
if you create a unique_ptr<T,D> yourself based on a new T pointer, the custom deleter D will have the responsibility to delete T. If you don't, you will leak memory (example).
A better approach would therefore be to keep using the default deleter, and make sure that T's destructor will clean or close anything needed.
And once you go for a default deleter, the best would be to go for make_unique that has some advantages over the new approach (see here why)
You are making your use of std::unique_ptr more complicated than it needs to be. DO NOT store a FILE** pointer inside the unique_ptr, store a FILE* instead. That is what fopen_s() outputs, and all access to the FILE is done through FILE* not FILE**. You don't need 2 levels of indirection when 1 level will suffice.
Try this:
#include <Windows.h>
#include <memory>
#include <string>
#include <map>
class File
{
private:
//functors - custom deleter
struct Close { void operator()(FILE* f); };
//type definitions
typedef std::unique_ptr<FILE,File::Close> Handle;
typedef std::map<std::string,Handle> HandleMap;
//static members
static Handle& Open(std::string _name, std::string _mode);
static HandleMap s_handle_map_;
//variables
Handle& handle_;
std::string name_;
public:
//functions
File(std::string _name, std::string _mode);
void Write(std::string _message);
};
File::HandleMap File::s_handle_map_;
File::File(std::string _name, std::string _mode)
: handle_(Open(_name,_mode)), name_(_name)
{
}
File::Handle& File::Open(std::string _name, std::string _mode)
{
auto iter = s_handle_map_.find(_name);
if (iter == s_handle_map_.end())
{
FILE *f = nullptr;
//open new file
if (fopen_s(&f, _name.c_str(), _mode.c_str()) != 0)
throw std::runtime_error("cannot open file");
//transfer ownership of handle
iter = s_handle_map_.emplace(_name, Handle(f)).first;
}
return iter->second;
}
void File::Close::operator()(FILE* f)
{
if (f)
fclose(f);
}
void File::Write(std::string _message)
{
fprintf(handle_.get(), "%s", _message.c_str());
}
int WINAPI WinMain(HINSTANCE _instance, HINSTANCE _previous, LPSTR _cmd, int _show)
{
File file("test.txt", "w");
file.Write("Hello World\n");
return 0;
}

Can a native application use registration-free COM to consume a .NET COM component?

Q: Can I make a native client that consumes a .NET COM component, using reg free COM?
I.e. Can I make a C++ application with COM info in its manifest, instead of registering the component (COM 'stuff') in the registry?
Note: I started looking at reg free COM with this question in mind, and didn't find a quick answer via web search. When I found the answer, thought'd I'd post on SO in case helps anyone else searching...
Yes.
And here's an MSDN has an article (from 2005) that walks through a working example of:
...the registration-free activation of a .NET Framework-based component by native clients via COM interop. (11 printed pages)
https://msdn.microsoft.com/en-us/library/ms973915.aspx (accessed Jan 2015)
Daryn,
This blog entry explain you how to do it:
http://blogs.msdn.com/b/rodneyviana/archive/2015/08/24/pure-native-c-consuming-net-classes-without-com-registration.aspx
Basically you use a entry point to return the pointer to the interface (using DllExport Nuget for "export"):
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using RGiesecke.DllExport;
namespace ContosoCom
{
public static class Exports
{
[DllExport(CallingConvention = CallingConvention.Cdecl)]
public static void GetClass([Out] [MarshalAs((UnmanagedType.Interface))] out IMyClass pInterface)
{
pInterface = new MyClass();
}
}
[ComVisible(true)]
[System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyClass
{
void DisplayMessageBox([MarshalAs(UnmanagedType.BStr)] string Text);
void GetTicksAndDate([Out] out MyStruct Structure);
}
[ComVisible(true)]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct MyStruct
{
public long TicksOfNow;
public int Day;
public int Month;
public int Year;
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IMyClass))]
public class MyClass : IMyClass
{
public void DisplayMessageBox(string Text)
{
MessageBox.Show(Text);
}
public void GetTicksAndDate(out MyStruct Structure)
{
Structure.TicksOfNow = DateTime.Now.Ticks;
Structure.Day = DateTime.Now.Day;
Structure.Month = DateTime.Now.Month;
Structure.Year = DateTime.Now.Year;
}
}
}
And this is how the C++ code looks like:
#include "stdafx.h"
#import "..\..\bin\Debug\ContosoCom.tlb" auto_rename
using namespace ContosoCom;
typedef void(*pGetClass)(IMyClass **iMyClass);
int _tmain(int argc, _TCHAR* argv[])
{
pGetClass getClass = NULL;
IMyClass *mc = NULL;
HINSTANCE hDLL = 0;
// load the DLL
hDLL = ::LoadLibrary(L"ContosoCom.dll");
::CoInitialize(NULL);
if(!hDLL)
{
printf("ERROR: Unable to load library ContosoCom.dll\n");
return -1;
}
//
// TO DO: Add code here to get an instance of MyClass
//
getClass = (pGetClass)GetProcAddress(hDLL, "GetClass");
if(!getClass)
{
printf("ERROR: Unable to find entry for GetClass()\n");
return -1;
}
getClass(&mc);
// At this point we do not have how to get a pointer even with the libray loaded
// End of TO DO
if(!mc)
{
printf("ERROR: Unable to get a pointer for MyClass\n");
return -1;
}
mc->DisplayMessageBox("Hello World from native to .NET without registration");
MyStruct st;
ZeroMemory(&st, sizeof(MyStruct));
mc->GetTicksAndDate(&st);
printf("Ticks %I64i\n",st.TicksOfNow);
printf("Today is %i/%i/%i\n",st.Month,st.Day,st.Year);
printf("SUCCESS: Leaving gracefully\n");
return 0;
}

pass member function from C++ CLI to native C callback

I've got problems passing a member function of a C++ CLI class to a native C callback from a library.
To be precise its the Teamspeak 3 SDK.
You can pass a non member function using the following code without problem:
struct ClientUIFunctions funcs;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = onConnectStatusChangeEvent;
But I need to pass a pointer to a member function, for example:
funcs.onConnectStatusChangeEvent = &MyClass::onConnectStatusChangeEvent;
Any other idea how to use the event within a non static member function is welcome to.
Thanks in advance!
This can only be done via a static class function because C doesn't know anything about the vtable or what object the function is part of. See below for a C++ and Managed C++ example
This could however be a work around, build a wrapper class which handles all the callbacks you need.
#include <string.h>
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
class CCallback
{
public:
CCallback()
{
struct ClientUIFunctions funcs;
// register callbacks
my_instance = this;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
~CCallback()
{
// unregister callbacks
my_instance = NULL;
}
static void sOnConnectStatusChangeEvent(void)
{
if (my_instance)
my_instance->OnConnectStatusChangeEvent();
}
private:
static CCallback *my_instance;
void OnConnectStatusChangeEvent(void)
{
// real callback handler in the object
}
};
CCallback *CCallback::my_instance = NULL;
int main(int argc, char **argv)
{
CCallback *obj = new CCallback();
while (1)
{
// do other stuff
}
return 0;
}
Another possibility would be if the callback supports and void *args like void (*onConnectStatusChangeEvent)(void *args); which you can set from the plugin. You could set the object in this args space so in de sOnConnectStatusChangeEvent you would have something like this:
static void sOnConnectStatusChangeEvent(void *args)
{
if (args)
args->OnConnectStatusChangeEvent();
}
For managed C++ it should be something like this, however I can't get it to compile because it doesn't like the template brackets..
wrapper.h:
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Text;
namespace Test
{
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
public delegate void ConnectStatusChangeEvent(void);
public ref class ManagedObject
{
public:
// constructors
ManagedObject();
// destructor
~ManagedObject();
//finalizer
!ManagedObject();
event ConnectStatusChangeEvent^ OnConnectStatusChangeEvent {
void add(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Combine(m_connectStatusChanged, callback));
}
void remove(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Remove(m_connectStatusChanged, callback));
}
void raise(void) {
if (m_connectStatusChanged != nullptr) {
m_connectStatusChanged->Invoke();
}
}
}
private:
ConnectStatusChangeEvent^ m_connectStatusChanged;
};
class CCallback
{
public:
static void Initialize(ManagedObject^ obj);
static void DeInitialize(void);
private:
static void sOnConnectStatusChangeEvent(void);
static gcroot<ManagedObject^> m_objManagedObject;
};
}
wrapper.cpp:
#include <string.h>
#include "wrapper.h"
using namespace System;
using namespace Test;
void CCallback::Initialize(ManagedObject^ obj)
{
struct ClientUIFunctions funcs;
// register callbacks
m_objManagedObject = obj;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
void CCallback::DeInitialize(void)
{
// unregister callbacks
m_objManagedObject = nullptr;
}
void CCallback::sOnConnectStatusChangeEvent(void)
{
if (m_objManagedObject != nullptr)
m_objManagedObject->OnConnectStatusChangeEvent();
}
// constructors
ManagedObject::ManagedObject()
{
// you can't place the constructor in the header but just for the idea..
// create wrapper
CCallback::Initialize(this);
}
// destructor
ManagedObject::~ManagedObject()
{
this->!ManagedObject();
}
//finalizer
ManagedObject::!ManagedObject()
{
CCallback::DeInitialize();
}
gcroot<ManagedObject^> CCallback::m_objManagedObject = nullptr;
int main(array<System::String ^> ^args)
{
ManagedObject^ bla = gcnew ManagedObject();
while (1)
{
// do stuff
}
return 0;
}

Calling C++ function from C#

I have a the following C++ function
void FillAndReturnString(char ** someString)
{
char sourceString[] = "test";
*someString = new char[5];
memcpy(*someString, sourceString, 5);
}
It is declared as
extern "C"
{
__declspec(dllexport) void __cdecl FillAndReturnString(char ** someString);
}
How do I call this function from C#?
Thanks
With P/Invoke.
You need to know that you're allocating unmanaged memory block in your c++ function, so it will not be possible to pass a managed String or Array object from C# code to 'hold' the char array.
One approach is to define 'Delete' function in your native dll and call it to deallocate the memory. On the managed side, you can use IntPtr structure to temporarily hold a pointer to c++ char array.
// c++ function (modified)
void __cdecl FillAndReturnString(char ** someString)
{
*someString = new char[5];
strcpy_s(*someString, "test", 5); // use safe strcpy
}
void __cdecl DeleteString(char* someString)
{
delete[] someString
}
// c# class
using System;
using System.Runtime.InteropServices;
namespace Example
{
public static class PInvoke
{
[DllImport("YourDllName.dll")]
static extern public void FillAndReturnString(ref IntPtr ptr);
[DllImport("YourDllName.dll")]
static extern public void DeleteString(IntPtr ptr);
}
class Program
{
static void Main(string[] args)
{
IntPtr ptr = IntPtr.Zero;
PInvoke.FillAndReturnString(ref ptr);
String s = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine(s);
PInvoke.Delete(ptr);
}
}
}