I'm writing a C# com library. I need a function that takes string from C++ and modifies string, after I have modified this string in my library modified value should be usable by C++ code. Here is my function (it's not working),
C# Interface,
Int32 testString([param: MarshalAs(UnmanagedType.LPStr)] ref string strData);
C# Implementation,
class Test:ITest
{
public int testString(ref string strData)
{
strData = strData + strData;
Console.WriteLine("strData in lib :"+strData);
return 0;
}
}
C++ code (I missed the parts, registering com lib, importing tlb etc.),
ITest * mInterface = NULL;
//...initilizing interface , skipped since this parts has no problem
LPSTR tt = "OLA";
mInterface ->testString(&tt); //It crashes when comes here ..
cout << tt <<endl;
I have found a solution to my problem , I am not sure but maybe we cannot initilized object from c++ to c# using com interop.If a use a null pointer to c# com , and initilize that pointer inside c# library code it worked .You can see the sample below ;
c# library interface
int testString(out string val);
c# library imp
class Test
{
int testString(out string val)
{
val = "Hello world"; //now user of this method can use val
return 0;
}
}
c++ usage
#pragma warning (disable: 4278)
#import "../yourtlb.tlb" no_namespace named_guids
ITestInterface * fpInterface = NULL;
int retval = 1;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_Test ,
NULL, CLSCTX_INPROC_SERVER,
IID_ITestInterface, reinterpret_cast<void**>(&fpInterface));
if(!FAILED(hr))
{
BSTR val = NULL;
int ret = fpInterface->testString(val);
cout <<val<<endl;
}
Of course before using code in c++ , dont forget to generate tlb file from your c# project , and dont forget to edit registry files.Here you can see a good sample
Related
I have the following C++ function from the MyCppLib.h file of a third party library:
int CppFunc(int Index, wchar_t* String, int StringLength);
where the maximum length of String is StringLength. String is returned by the function (out).
I am trying to wrap this in C++/CLI for use in C#. According to this page it looks like StringBuilder should be used to marshall wchar_t* back to C++/CLI.
So I believe the C++/CLI should look something like this:
#include "MyCppLib.h"
using namespace System;
using namespace System::Text;
namespace MyCppCliLib
{
int CppCliFunc(int Index, StringBuilder^ sB, int StringLength) {
return ::CppFunc(Index, ???, StringLength);
}
}
Now, how can I retrieve the wchar_t* from C++ back to StringBuilder^ ? I can't find a good example on the topic...
I believe the C# side would then looks like:
StringBuilder sB = new StringBuilder();
int x = CppCliFunc(2, sB, 4096);
EDITS:
Thanks to all the comments, I finally got something working, it looks like this (don't quote me on it, it's my first steps in C++/CLI):
#include "MyCppLib.h"
#include <string.h>
#include <stdlib.h>
using namespace System;
using namespace System::Text;
namespace MyCppCliLib
{
String^ CppCliFunc(int Index, int StringLength) {
String^ newString="";
wchar_t* wchar = (wchar_t*)calloc(StringLength, sizeof(wchar_t));
if (wchar != NULL) {
int errorInt = ::CppFunc(Index, wchar, StringLength);
newString = gcnew String(wchar);
if(errorInt != 0){
throw gcnew Exception("Error #" + errorInt.ToString());
}
}else{
throw gcnew Exception("Error wchar is null");
}
free(wchar);
return newString;
}
}
I'm trying to get out an array in a pythonic format [numpy or list] form a DLLwritten in c#/c++. This DLL gives out the pointer to the memory and not the evaluated array. How can I access the memory in a FAST way (I wrote the DLL to speedup the code)?
I have used the pythonnet module and i managed to get the memory pointer as a but I'm failing in extracting the memory pointer as an integer or binary and then to get the data of the output vector.
Here the python code:
import numpy as np
import clr
clr.AddReference(R'...\PyDLL.dll')
from PyDLL import StringLibrary
my_instance = StringLibrary()
x = my_instance.arrayShift(np.array([1,2,3,4,5,6,7,8,9,0]).reshape(-1))
And then the C# code
namespace PyDLL
{
public class StringLibrary
{
public static double[] arrayShift(double[] array)
{
int b = array.Length;
double[] newArray = new double[b];
for(int i=0; i<b; i++)
{
newArray[i] = array[b-i-1];
}
return newArray;
}
}
}
I expect that the output x in python is a list or a np array, while now it is a System.Double[] object.
the expected output of x is [0,9,8,7,6,5,4,3,2,1]
Thank you for any help
After many tries and researches, I managed to solve the problem in this way:
Cpp part:
Open Visual Studio, then create a new project (Dynamic-Link Library).
Name the project and add a new file in the project (Header file) and name it with the same project name.
Insert the following code in the header:
// headerName.h - Contains declarations of math functions
#pragma once
#ifdef HEADERNAME_EXPORTS
#define HEADERNAME_API __declspec(dllexport)
#else
#define HEADERNAME_API __declspec(dllimport)
#endif
// Define the functions that will be called using the DLL
extern "C" HEADERNAME_API void funName1(...);
extern "C" HEADERNAME_API void funName2(...);
extern "C" HEADERNAME_API void funName3(...);
...;
In the folder 'Source Files' add a new file with extension .cpp (call it with the same name as the project), then write the function in this .cpp file. Here an example code:
#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier COMPULSORY TO ADD
#include "HEADERNAME.h" // COMPULSORY TO ADD
#include lib#1
#include lib#2
#include lib#3
...
using namespace std;
void funName1(...)
{
...
}
void funName2(...)
{
...
}
void funName3(...)
{
...
}
To be able to pass the arrays between python and c++, in my solution, the use of pointers is needed and no return must be used. The output variable is passed as an input variable, initialized in python, using a pointer. In the DLL the memory cells of the output variables are re-wrote and, doing so, when the DLL completes the function, the output is computed and already usable by python without return.
Here an example of how to write a function using pointers for input and output arrays:
void funName(double* inputArray_pointer, double* outputArray_pointer, int extraVariable)
{
double inner_var = 100;
for (int i = 0; i < extraVariable; i++)
{
inner_var = min(inner_var, *(inputArray_pointer+i));
*(outputArray_pointer + i) = inner_var;
}
}
Then rebuild the DLL.
Python part
To use correctly a DLL in the python code, the modules 'ctypes' and 'numpy' must be imported.
Here follows an example of the python code (This will use the example DLL of point (9)):
import numpy as np
import ctypes
cpp_fun = ctypes.CDLL(R'pathToDll/DLLname.dll')
# Define the types of the arguments of the DLL (pointer, int, double, ecc)
cpp_fun.funName.argtypes = [np.ctypeslib.ndpointer(),
np.ctypeslib.ndpointer(),
ctypes.c_int]
# Allocate or define the input variables using numpy or the standard scalar of python (int, float, ecc..)
inputArray = np.array([0,1,2,3,4,5,6,7,8,9,...,1000]).reshape(-1).astype('f8')
outputArray = np.zeros([inputArray.shape[0]])astype('f8')
extraVariable = inputArray.shape[0]
cpp_fun.funName(inputArray, outputArray, extraVariable)
Doing so, in the variable 'outputArray' we will find the result of the calculations performed inside the DLL as a np array structure.
I'm using a Dll created from a C++ file. When I either put the .dll and .lib files in my Unity-project folder or when I use the function that I need, Unity crashes and I can't open the project untile I remove the .dll or delete the function from the c# script.
This function works well on C++, both in Visual Studio and in Dev-C++
PS: Assets/alzBraccioCorretto.json is the file that I need to read
I've tried the same procedure for more simple dlls and it worked fine, so I don't know what I'm missing with this one.
In the Unity script I wrote
[DllImport("QuartaLibreria.dll", CharSet = CharSet.Unicode)]
static extern int LeggiFile(string nomeFile);
Text testo;
unsafe void Start()
{
testo = GetComponent<Text>();
int temp = 0;
temp = LeggiFile("Assets/alzBraccioCorretto.json");
testo.text = temp.ToString();
}
In the header of the library I have
#define QUARTALIBRERIA_API __declspec(dllexport)
//all the other headers and #include
int converti_int(string frame);//returns reads a line and returns an int
int leggiFile(string nomeFile);
extern "C" {
QUARTALIBRERIA_API int LeggiFile(wstring nomeFile);
}
In the cpp of the library I have
int leggiFile(string nomeFile) {
ifstream _stream(nomeFile.c_str());
int temp;
_stream >> temp >> temp >> temp >> temp >> temp;
return temp;
}
QUARTALIBRERIA_API int LeggiFile(wstring nomeFile){
std::string str = std::string(nomeFile.begin(), nomeFile.end());
int daRit = leggiFile(str);
return daRit;
}
I am working on my master thesis and need your help! Btw I am studying mechanical enginneering... so my programming skills are limited.
Here my problem:
I have a DLL, which is created in C# ( I cannot post it, because it is a part of an unpublished research). But it gives me some Arrays ( 1D-Array [], 2DArray[,] ).
For a simulation with ABAQUS I need to import that C#-DLL in C++ and/or FORTRAN.
I found the solution from Robert Giesecke to create a unmanaged DLL. I think this is the easiest solution for me. (Of course if someone has another solution for me, a wrapper or something, please post it)
Here my 1D Array example for a unmanaged C#-DLL created with R.Giesecke Template:
using System;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace Testme
{
class Test
{
[DllExport("Get1DArray", CallingConvention = CallingConvention.StdCall)]
public static double Get1DArray([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] STRESS, int i)
{
return STRESS[i];
}
}
}
and here my 2D Array code:
using System;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
namespace Testme
{
class Test
{
public static int idx(int a, int b) { int cols = 2; return a * cols + b; }
[DllExport("Set2DArray", CallingConvention = CallingConvention.StdCall)]
public static int Set2DArray([In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] int[] STRAIN, int len)
{
STRAIN[idx(0, 0)] = 0;
STRAIN[idx(0, 1)] = 1;
STRAIN[idx(1, 0)] = 2;
STRAIN[idx(1, 1)] = 3;
STRAIN[idx(2, 0)] = 4;
STRAIN[idx(2, 1)] = 5;
return 0;
}
}
}
The Build have succeeded at both. How can I import the DLLs in C++ and/or FORTRAN?
Thx in advance!
When you compile your C#-DLL with tool from R. Giesecke, you should also get a *.lib file with it.
You need to reference this lib in your FORTRAN linker settings as additional library dependency. It contains all the code required to load the DLL and make the functions in the DLL available.
In your FORTRAN code you need to declare the imported methods with the following statements:
!DEC$ ATTRIBUTES DLLIMPORT, ALIAS:'_MethodeName::MethodName
BTW: COM visibility is not needed if using RGiesecke. The access to the C# is native and not via COM (also making it considerably faster).
When using the NI tools to create a FPGA bit file, LabView generates a C .h file that contains information for communicating to the FPGA application such as the signature (a const) and the register addresses (as enums).
The challenge is that my application is written in C# and I need access to those register addresses.
The only options I can think of are:
Cut-and-paste the contents of the .h file into a .cs file ~~~~ ... gives me the shivers, C# is one developer and FPGA is another.
Parse the .h file ~~~~ ... gives me the shivers too - writing my own language parser :(
There has got to be a better way!!!
Sample .h:
/*
* Generated with the FPGA Interface C API Generator 12.0.0
* for NI-RIO 12.0.0 or later.
*/
#ifndef __NiFpga_M_OTRM_OVDFPGA_h__
#define __NiFpga_M_OTRM_OVDFPGA_h__
#ifndef NiFpga_Version
#define NiFpga_Version 1200
#endif
#include "NiFpga.h"
/**
* The filename of the FPGA bitfile.
*
* This is a #define to allow for string literal concatenation. For example:
*
* static const char* const Bitfile = "C:\\" NiFpga_M_OTRM_OVDFPGA_Bitfile;
*/
#define NiFpga_M_OTRM_OVDFPGA_Bitfile "NiFpga_M_OTRM_OVDFPGA.lvbitx"
/**
* The signature of the FPGA bitfile.
*/
static const char* const NiFpga_M_OTRM_OVDFPGA_Signature = "D0751ADE3A0EC976606D63C425B35E85";
typedef enum
{
NiFpga_M_OTRM_OVDFPGA_IndicatorBool_FallingEdge = 0x8132,
NiFpga_M_OTRM_OVDFPGA_IndicatorBool_StopSignal = 0x813A,
} NiFpga_M_OTRM_OVDFPGA_IndicatorBool;
....
#endif
given its likely only a tiny subset of things you need to parse, in fact, it won't have to parse but probably just do a few text manipulations / search replaces. It shouldn't be too hard. Also, you can use C++.NET to wrap the things into an API you can use from C#.
Also you may want to look at something like 'SWIG'
http://www.swig.org/
I solved the problem by adding a C++/CLI project to the solution that includes the .h file and exposes the information through managed static methods.
public ref class OTRM_Ovd_FPGA
{
public:
static System::String^ GetFilename() { return gcnew System::String(NiFpga_M_OTRM_OVDFPGA_Bitfile);};
static System::String^ GetSignature() { return gcnew System::String(NiFpga_M_OTRM_OVDFPGA_Signature);};
enum class RegisterAddress : System::UInt16
{
InitialPulseAmplitude = NiFpga_M_OTRM_OVDFPGA_IndicatorU16_ExtPulseAmplitudeDisplay,
CurrentPulseAmplitude = NiFpga_M_OTRM_OVDFPGA_IndicatorU16_ExtPulseAmplitudeDisplay,
PulseAmplitudeDecrement = NiFpga_M_OTRM_OVDFPGA_ControlU16_Decrement_Step,
PollPeriod = NiFpga_M_OTRM_OVDFPGA_ControlI16_Frequency_ms,
HvprotState = NiFpga_M_OTRM_OVDFPGA_ControlI16_HVProt,
PaceThreshold = NiFpga_M_OTRM_OVDFPGA_ControlI16_VVIThreshold,
};
};