In C# with DLLImport need to call C++ custom type variable and pointers.
Custom Types:
typedef unsigned char UN_Char;
typedef enum { Valid = 0, Invalid = 1, Unknown = -999 } AppResponseCode;
Called in SomeAPI.C
static AppResponseCode SomeFunction(UN_Char ** vUC1PtrPtr,size_t * vSize1Ptr, UN_Char * vUC2Ptr,size_t vSize2, FILE * inputFile, char * vcharPtr)
Now I need to Call C++ Function from C#.
Once I tried to create Reference its failed witht the message
A Reference to '.....\SomeApi.DLL' could not be added. Please make sure that the file is accessible, and that it is valid assembly or COM Component
So I go with other route to Import DLL using DLLImport but here I don't have signature for the calling C++ Function
[DllImport("SomeAPI.dll", CharSet = CharSet.Unicode)]
public static extern ?AppResponseCode? SomeFunction( ?????emphasized text ) ;
Can someone help me to identify Function Signature ?
How can I create an instance for a class in c# dll that I imported in a c++ project? I have imported the c# library to c++ by following the instructions given here. I can call the functions using the public interface.
[EDIT] I want to set values for the attributes of the class in c# dll through c++ and to pass it to the dll. So that I can skip so many set functions in c# dll. If I can create object for the class, I will set the values using the object and pass the object to c# dll.
In the link you provided, in the c++ client code description
// CPPClient.cpp: Defines the entry point for the console application.
// C++ client that calls a managed DLL.
#include "stdafx.h"
#include "tchar.h"
// Import the type library.
#import "..\ManagedDLL\bin\Debug\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
int _tmain(int argc, _TCHAR* argv[])
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
ICalculatorPtr pICalc(__uuidof(ManagedClass));
long lResult = 0;
// Call the Add method.
pICalc->Add(5, 10, &lResult);
wprintf(L"The result is %d\n", lResult);
// Uninitialize COM.
CoUninitialize();
return 0;
}
the creation of the pointer, pICalc is the pretty much the creation of the object of the class. Created in the line ICalculatorPtr pICalc(__uuidof(ManagedClass));
I am following the example in How to call a managed DLL from native Visual C++ code in Visual Studio.NET or in Visual Studio 2005 to call a .NET DLL from native C++ code. The code for C# looks like this:
public class StringExample: IStringExample
{
public string returnString(string input)
{
return input;
}
}
I followed the example's steps to build, register the COM assembly, and export the type library (.tlb) from the C# code.
In C++ code, I am trying to use code similar to the following:
#import "..\StringExample\bin\Debug\StringExample.tlb" raw_interfaces_only
using namespace StringExample;
void abc()
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
// Create the interface pointer.
IStringExample ptr(__uuidof(StringExample));
BSTR bstrInput = L"hello world";
BSTR bstrOutput =L"";
ptr->returnString(bstrInput, &bstrOutput);
TCHAR* szOutput = (TCHAR *)_bstr_t(bstrOutput);
// Uninitialize COM.
CoUninitialize();
}
However, bstrOutput is empty. Moreover, I need to convert the bstrOutput to TCHAR* to pass it to a different api.
Is there an error in the variable initialization? Is there a different way to pass string variables between .NET and C++?
How to pass objects from C# library to C++.
I can call a function which returns void or int without any issue.
Now consider the following function in C#,
List<CSharpClass> CSharpFunction(string Input)
where my C# class contains,
public class CSharpClass
{
string mystring = string.Empty;
byte[] bytearray = null;
public byte[] bytearray
{
get { return bytearray ; }
set { bytearray = value; }
}
public string mystring
{
get { return mystring ; }
set { mystring = value; }
}
}
Now, I want use this List in my C++. So I have created,
typedef std::vector<class CSharpClass> MyDetailList;
Is it the right way ?? If not what I need to use in C++?
If you want to call a C# dll from C++ code, you can follow this article.
In a nutshell, you're going to have to:
- Write a Managed DLL containing your CSharpClass
- Register the Managed DLL for Use with COM or with Native C++
- Call the Managed DLL from Native C++ Code
This SO question is also relevant, and contains alternative solutions if you want to avoid using COM
Initial misguided answer:
You can check this article for a fairly good tutorial.
In a nutshell, you're going to have to:
- Compile a dll from your c++ code
- marshall ("translate") your class between C# and C++
- load the dll from C#, by using DllImport declaration
- call the imported method
I want to pass some image data from C# code to unmanaged C++ using ATL/COM
From C# code side i do something like this:
void SendFrame([In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UI1)] ref byte[] frameData);
But I'm not sure how should I handle this function in my C++ code.
For now I have something like this:
_ATL_FUNC_INFO OnSendFrameDef = { CC_STDCALL, VT_EMPTY, 1, { VT_SAFEARRAY | VT_UI1 } };
void __stdcall OnSendFrame(SAFEARRAY* ppData)
{
BYTE* pData;
SafeArrayAccessData(ppData, (void **) &pData);
// Doing some stuff with my pData
SafeArrayUnaccessData(ppData);
}
Can anyone give me some suggestions how I can make this thing work?
Thanks.
Since the SAFEARRAY is already marshaled to your unmanaged code, and you're using ATL, you can use the CComSafeArray class, as it handles all the cleanup when working with SAFEARRAY instances:
_ATL_FUNC_INFO OnSendFrameDef = { CC_STDCALL, VT_EMPTY, 1,
{ VT_SAFEARRAY | VT_UI1 } };
void __stdcall OnSendFrame(SAFEARRAY* ppData)
{
// Wrap in a CComSafeArray.
// On the stack means all calls to cleanup
// will be cleaned up when the stack
// is exited.
CComSafeArray<byte> array;
array.Attach(ppData);
// Work with the elements, get the first one.
byte b = array.GetAt(0);
// And so on. The destructor for CComSafeArray
// will be called here and cleaned up.
}
I've managed to achieve my goal! For those who are interested:
My event handler descriptor looks like this:
_ATL_FUNC_INFO Stream::OnStreamFrameCallbackDef = { CC_STDCALL, VT_EMPTY, 1, { VT_DISPATCH } };
My C++ function:
void __stdcall Stream::OnStreamFrameCallback(IDispatch* pFrame)
{
// NOTE that this "IStreamFramePtr" is COM's Ptr of my "IStreamFrame"
MyCOM::IStreamFramePtr pStreamFrame = pFrame;
// Thanks casperOne♦ for this:
CComSafeArray<byte> array;
array.Attach(pStreamFrame->GetBuffer());
// Now I can do stuff that I need...
byte* pBuffer = &array.GetAt(0);
}
My "IStreamFrame" in my .tlh file looks like this:
struct __declspec(uuid("1f6efffc-0ac7-3221-8175-5272a09cea82"))
IStreamFrame : IDispatch
{
__declspec(property(get=GetWidth))
long Width;
__declspec(property(get=GetHeight))
long Height;
__declspec(property(get=GetBuffer))
SAFEARRAY * Buffer;
long GetWidth ( );
long GetHeight ( );
SAFEARRAY * GetBuffer ( );
};
In my C# code I have something like this:
[ComVisible(true)]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface IStreamFrame
{
int Width { [return: MarshalAs(UnmanagedType.I4)] get; }
int Height { [return: MarshalAs(UnmanagedType.I4)] get; }
byte[] Buffer { [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UI1)] get; }
};
[ComVisible(false)]
public delegate void StreamFrameCallback(IStreamFrame frame);
[ComVisible(true)]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyCOMStreamEvents
{
[DispId(1)]
void OnStreamFrameCallback([In, MarshalAs(UnmanagedType.IDispatch)] IStreamFrame frame);
}
Things seems to work just fine. But if anyone have any suggestions or noticed that I'm doing something wrong please let me know.
Thanks.
I strongly recommend you to create an IDL file to design your COM interfaces.
Given your example in your answer, a rather minimal IDL file could be like this:
import "oaidl.idl";
[object,
uuid(1f6efffc-0ac7-3221-8175-5272a09cea82),
dual,
oleautomation]
interface IStreamFrame : IDispatch {
[propget]
HRESULT Width([out, retval] long *pWidth);
[propget]
HRESULT Height([out, retval] long *pHeight);
[propget]
HRESULT Buffer([out, retval] SAFEARRAY(byte) *pBuffer);
};
[uuid(1f6efffc-0ac7-3221-8175-5272a09cea83)]
library ContosoStreamFrame {
importlib("stdole32.tlb");
interface IStreamFrame;
};
You then use midl.exe to generate a .h with C/C++ interfaces, a _i.c for the CLSID and IID constants for C/C++ linking, a dlldata.c for RPC registering, a _p.c with proxy and stub marshalling stuff and a .tlb which is in general terms the parsed representation of the .idl file. This is all better described in the documentation.
EDIT: There seems to be no way to avoid the C/C++ file generation.
EDIT2: I just found a workaround, use nul as the output file for what you don't want. For instance, the following command only generates file.tlb:
midl.exe /header nul /iid nul /proxy nul /dlldata nul file.idl
Note: if your IStreamFrame interface is not meant to be used across processes, add the local attribute to the interface.
In C/C++, you can use the specific files that are generated, or #import the TLB file. In .NET, you can run tlbimp.exe on the TLB file, which generates a .NET assembly.
You can also use tlbexp.exe if your project is .NET centric. However, that'll require you to know the .NET COM annotations and what they mean in terms of IDL, so I'm not sure if there's any gain on saving one extra source-file in another language at the expense of lots of decoration noise in your interface and class definitions. It's perhaps a good option if you want to have full control of the classes and interfaces at the source level and you want to make it as easy as possible (read, optimized for usability and maybe speed) on .NET code.
Finally, you can automate all of this in Visual Studio by creating a project. If you use the IDL approach, add a custom build step that invokes midl.exe and tlbimp.exeand make the dependant projects depend on this project for a correct build order. If you use the .NET approach, add a custom build step that invokes tlbexp.exe and make the dependant C/C++ projects depend on this project.
EDIT: If you don't need the generated C/C++ files from midl.exe, you may add del commands to your custom build step for the specific output files.
EDIT2: Or use the nul workaround described above.
A common approach used when the type library already exists is to use Visual Studio to import it into .NET. But this way, you'll have to remember to regenerate the TLB and import it again if you update your IDL file.
Have you considered C++/CLI? In your C++/CLI ref class you'd write a member function:
void SendFrame(cli::array<System::Byte> frameData)
{
pin_ptr<System::Byte> p1 = &frameData[0];
unsigned char *p2 = (unsigned char *)p1;
// So now p2 is a raw pointer to the pinned array contents
}