Get struct from C++ dll into a C# application - c++

I'm learning C# and have some experience with it. For a small project I need to implement a C++ dll into my C# app. It is a licenseplate recognition sdk.I can initialize it, so calling to this C++ code is working. But I have a problem to receive a struct back from the c++ code with strings in it. I tried a lot, read here a lot, but I don't get it working. This is C# side:
[DllImport("D:\\processor.dll", EntryPoint = "StartALPR", CallingConvention = CallingConvention.Cdecl)]
[return:MarshalAs(UnmanagedType.LPStruct)]
public static extern TMyData StartALPR(TImageSource tImageSource);
The C# struct TMyData :
[StructLayout(LayoutKind.Sequential)]
public struct TMyData
{
[MarshalAs(UnmanagedType.LPTStr)]
public string PlateString;
[MarshalAs(UnmanagedType.LPTStr)]
public string PlateXML;
[MarshalAs(UnmanagedType.LPTStr)]
public string LastError;
};
And this is the method we call to send tImageSource which contains a string with a filepath to an image to analyze.
alprResult = StartALPR(tImageSource);
The file is analyzed, so that's working. I can see the plate strings in the output of VS2015.
But I'm expecting a struct "alprResult" back as defined in TMydata, but I get an exception that the method sign is not compatible with the pinvoke sign. The only information I have is an example of how to use this dll/code in C++. This is the C++ code :
TImageSource SImageSource;
TMyData *pd;
/* Set input image */
SImageSource.MyImageFile = AnsiString(CarImage).c_str();
Memo1->Lines->Clear();
/* Starting plate detect and recognition */
pd = StartALPR(&SImageSource);
/* Standard XML result, the plate datas with numbers and positions */
Memo1->Lines->Add(pd->PlateXML);
/* last error message */
Memo2->Lines->Add(pd->LastError);
/* Best characters on plate */
Edit1->Text = pd->PlateString;
This is the C++ struct from the same example :
struct TMyData;
typedef TMyData *PMyData;
struct TMyData
{
/**
PlateString: Best license plate number of the plate group
*/
const char * PlateString;
/**
PlateXML: Plate group data in standard XML string
*/
const char * PlateXML;
/**
LastError: Laast config error ex: bad file extensions .. Default: empty
*/
const char * LastError;
};
How can I use this in C#?
Thanks in advance.

I actually had to solve a similar issue to this recently. I simply serialized the data into a struct and shipped it over a local zeromq socket.
//
// Weather update server in C++
// Binds PUB socket to tcp://*:5556
// Publishes random weather updates
//
// Olivier Chamoux <olivier.chamoux#fr.thalesgroup.com>
//
#include <zmq.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if (defined (WIN32))
#include <zhelpers.hpp>
#endif
#define within(num) (int) ((float) num * random () / (RAND_MAX + 1.0))
int main () {
// Prepare our context and publisher
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_PUB);
publisher.bind("tcp://*:5556");
publisher.bind("ipc://weather.ipc"); // Not usable on Windows.
// Initialize random number generator
srandom ((unsigned) time (NULL));
while (1) {
int zipcode, temperature, relhumidity;
// Get values that will fool the boss
zipcode = within (100000);
temperature = within (215) - 80;
relhumidity = within (50) + 10;
// Send message to all subscribers
zmq::message_t message(20);
snprintf ((char *) message.data(), 20 ,
"%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(message);
}
return 0;
}
and now the client
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using ZeroMQ;
namespace Examples
{
static partial class Program
{
public static void WUClient(string[] args)
{
//
// Weather update client
// Connects SUB socket to tcp://127.0.0.1:5556
// Collects weather updates and finds avg temp in zipcode
//
// Author: metadings
//
if (args == null || args.Length < 2)
{
Console.WriteLine();
Console.WriteLine("Usage: ./{0} WUClient [ZipCode] [Endpoint]", AppDomain.CurrentDomain.FriendlyName);
Console.WriteLine();
Console.WriteLine(" ZipCode The zip code to subscribe. Default is 72622 Nürtingen");
Console.WriteLine(" Endpoint Where WUClient should connect to.");
Console.WriteLine(" Default is tcp://127.0.0.1:5556");
Console.WriteLine();
if (args.Length < 1)
args = new string[] { "72622", "tcp://127.0.0.1:5556" };
else
args = new string[] { args[0], "tcp://127.0.0.1:5556" };
}
string endpoint = args[1];
// Socket to talk to server
using (var context = new ZContext())
using (var subscriber = new ZSocket(context, ZSocketType.SUB))
{
string connect_to = args[1];
Console.WriteLine("I: Connecting to {0}…", connect_to);
subscriber.Connect(connect_to);
/* foreach (IPAddress address in WUProxy_GetPublicIPs())
{
var epgmAddress = string.Format("epgm://{0};239.192.1.1:8100", address);
Console.WriteLine("I: Connecting to {0}…", epgmAddress);
subscriber.Connect(epgmAddress);
}
} */
// Subscribe to zipcode
string zipCode = args[0];
Console.WriteLine("I: Subscribing to zip code {0}…", zipCode);
subscriber.Subscribe(zipCode);
// Process 10 updates
int i = 0;
long total_temperature = 0;
for (; i < 20; ++i)
{
using (var replyFrame = subscriber.ReceiveFrame())
{
string reply = replyFrame.ReadString();
Console.WriteLine(reply);
total_temperature += Convert.ToInt64(reply.Split(' ')[1]);
}
}
Console.WriteLine("Average temperature for zipcode '{0}' was {1}°", zipCode, (total_temperature / i));
}
}
}
}

Related

How to dump struct type data using protocol buffer?

I am using gRPC where I want to transfer a struct type object from server to client using protocol buffer. My desire is to directly dump the struct datatype in a message field.
Some of my sample code is given here
server.cpp where I am getting a struct type object from a function.
// sample struct
struct Dummy_Info{
int age;
bool presence;
};
// sample function to return struct
Dummy_Info Pass_Dummy_Info()
{
Dummy_Info obj;
obj.age = 54;
obj.presence = 1;
return obj;
}
sample.proto file which I desire to make(I am only using here the message which will be used for server purpose)
syntax = "proto3";
package abc_xyz;
// Response message from server to client
message Server_Response {
float val = 1;
// The following is my desire
struct variable_for_struct_object = 2;
}
// Request message from client to server
message Client_Request {
string name = 1;
}
service Service {
rpc GetAddress(Client_Request) returns (Server_Response) {}
}
server.cpp
// omitted the unnecessary part intentionally. Suppose I have passed the Server_Response as pointer type object and it is `response`
Dummy_Info result;
result = Pass_Dummy_Info();
// The following works flawlessly
response -> set_val(0.5);
// The following I want to prepare
response -> set_variable_for_struct_object(result);
client.cpp
// Here I need to fetch the struct type data
auto data = response_.variable_for_struct_object();
cout << data.presence << endl;
cout << data.age << endl;
I don't know this direct dumping is possible or not or maybe I am missing concept.
What I am doing right now:
sample.proto
syntax = "proto3";
package abc_xyz;
// The following I have added which mimics my struct type object
message DATA_TYPE{
int32 age = 1;
bool presence = 2;
}
// Response message from server to client
message Server_Response {
float val = 1;
// The following is my desire
DATA_TYPE variable_for_struct_object = 2;
}
// Request message from client to server
message Client_Request {
string name = 1;
}
service Service {
rpc GetAddress(Client_Request) returns (Server_Response) {}
}
After then I have formatted the cpp files as like as follows which is working
server.cpp
Dummy_Info result;
result = Pass_Dummy_Info();
response->mutable_variable_for_struct_object()->set_age(result.age);
client.cpp is as like as before.
Reason of my desire is to avoid declare the same struct 2 times (one time in cpp, later in proto message format). If here is any workaround would be grateful to have the direction.
protobuf holds similar data for struct. For more info about pb vs struct can be found at: https://developers.google.com/protocol-buffers/docs/cpptutorial
syntax = "proto3";
package communication;
message YourData {
int32 d1 = 1;
string d2 = 2;
}
// Response message from server to client
message Response {
int32 result = 1;
// struct obj_data = 2; // I know this will not work and which pushes me to ask the question.
YourData data = 2;
}
// Request message from client to server
message Request {
string name = 1
}
service Dummy_Service {
rpc GetAddress(Request) returns (Response) {}
}
server related code
YourData d;
d.set_d1(1);
d.set_d2("hello");
response->mutable_data()->CopyFrom(d)
client related code
auto data = response_.data();
cout << data.d1() << ":" << data.d2() << endl;

Using VC++ 6.0 COM DLL from Threads C#

BackGround:
We have DLL created using VC++6.0. This DLL in interface have functions that send message to our server. So external applications call function of our DLL by passing input parameter and our DLL send this message to a server using TCP/IP and return back a output for caller.
DLL is compiled with following settings
Main of DLL looks like this
I have created a samll application in C# (framework 2.0) that creates thread to call function of DLL. What happens is that second thread gets blocked until first thread has not finished the job.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using PAGAMENTOLib;
using log4net;
using log4net.Config;
using System.Configuration;
namespace ThreadTestAPI
{
class Program
{
public static ILog log = LogManager.GetLogger(typeof(Program));
argpayClass apiFunctions = new argpayClass();
static void Main(string[] args)
{
XmlConfigurator.Configure();
List<string> Ip_List = new List<string>();
List<string> Ip_port = new List<string>();
int MAX_THREAD = Convert.ToInt32(ConfigurationManager.AppSettings["MAX_THREAD"].ToString());
string ReplacePattern = string.Empty;
string IP = ConfigurationManager.AppSettings["IP"].ToString();
string PORT = ConfigurationManager.AppSettings["PORT"].ToString();
Program call = new Program();
//int LastPart = Convert.ToInt32(IP.Split('*')[1]);
//string PatterntoReplase = "*" + LastPart;
log.Info("-------------------------------------------------------------------------");
log.Info(" Started Program ");
log.Info("-------------------------------------------------------------------------");
List<Thread> ThreadList = new List<Thread>(); //Added by Asif Iqbal
WaitAllThreads waitThreads = new WaitAllThreads();
List<Thread> myPOSthread = new List<Thread>();
ParamIn param = new ParamIn();
for (int i = 0; i < MAX_THREAD; i++)
{
Thread thread = new Thread(new ParameterizedThreadStart(call.CallApiFunction));
thread.Name = "Thread " + i;
param.Ped_ip = IP;
log.Info("Thread Name is : " + thread.Name);
log.Info("IP is " + param.Ped_ip);
param.PedPort = PORT.Replace("*",i.ToString());
log.Info("Port is " + param.PedPort);
param.Amount = i;
param.port_listener = "0";
param.DatiAgg = "Thread " + i;
ThreadList.Add(thread);
thread.IsBackground = true;
thread.TrySetApartmentState(ApartmentState.MTA);
thread.Start(param);
myPOSthread.Add(thread);
Console.WriteLine("***********************************************************");
Console.WriteLine("Thread Name: " + thread.Name);
System.Threading.Thread.Sleep(250);
}
}
[MTAThread]
public void CallApiFunction(object param)
{
log.Info("Calling Api function");
ParamIn members = (ParamIn)param;
//argpayClass apiFunctions = new argpayClass();
string Response = string.Empty;
apiFunctions.PagamentoTCP(0,500,ref members.Ped_ip,Convert.ToInt32(members.PedPort),ref members.DatiAgg,ref Response);
log.Info("IP is " + members.PedPort + ".Response Received from Api is: " + Response);
}
}
public class ParamIn
{
public int Amount;
public string DatiAgg;
public string PedPort;
public string Ped_ip;
public string ip_listener;
public string port_listener;
public int tmo;
public int PrintTicket;
public int Advance;
public ParamIn()
{
Amount = 0;
DatiAgg = "";
Ped_ip = "";
PedPort ="";
port_listener = "";
ip_listener = "";
tmo = 0;
PrintTicket = 0;
}
}
}
I tried to use
CoInitializeEx(NULL, COINIT_MULTITHREADED);
in DLL main but no success. I also changed this but still same behavior
public CComObjectRootEx<CComSingleThreadModel>
to public CComObjectRootEx<CComMultiThreadModel>
Does anyone know why Function of dll doesn't get called until first thread is in progress?
Whereas in c# threads were created correctly. Each thread finish job but not in pralall of others. It has to wait.
If you know your object’s implementation is thread safe and you want to tell .NET about that, implement IMarshal interface in your COM object.
Use CoCreateFreeThreadedMarshaler to create the marshaler, return the marshaler when .NET asks for IMarshal interface through QueryInterface call.
If you’re using ATL to implement your object, look at my answer for more info.

How to wait for data on a COM port

I am using .Net framework's SerialPort class (System.IO.Ports) and am trying to wait to receive data. I've looked around and the WaitCommEvent function seems to be what people suggest using, however it expects a HANDLE as the first parameter. I would like to know either how to get a handle from the SerialPort or a different way to wait for data compatible with the SerialPort class.
The SerialPort class has a DataReceived event:
Indicates that data has been received through a port represented by the SerialPort object.
The documentation provides the following C++/CLI example:
#using <System.dll>
using namespace System;
using namespace System::IO::Ports;
ref class PortDataReceived
{
public:
static void Main()
{
SerialPort^ mySerialPort = gcnew SerialPort("COM1");
mySerialPort->BaudRate = 9600;
mySerialPort->Parity = Parity::None;
mySerialPort->StopBits = StopBits::One;
mySerialPort->DataBits = 8;
mySerialPort->Handshake = Handshake::None;
mySerialPort->RtsEnable = true;
mySerialPort->DataReceived += gcnew SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort->Open();
Console::WriteLine("Press any key to continue...");
Console::WriteLine();
Console::ReadKey();
mySerialPort->Close();
}
private:
static void DataReceivedHandler(
Object^ sender,
SerialDataReceivedEventArgs^ e)
{
SerialPort^ sp = (SerialPort^)sender;
String^ indata = sp->ReadExisting();
Console::WriteLine("Data Received:");
Console::Write(indata);
}
};
int main()
{
PortDataReceived::Main();
}

Serial COM Programming : Random Numbers

i need a little help with my coding.. see the coding below is used if we were to write a string and send through a com port.. what if we were to generate random strings and send it through a com port.. what do i actually have to change in the "this->serialPort1->WriteLine(message);" ? tried several codes from google.. none of them are working
private: System::Void button4_Click(System::Object^ sender, System::EventArgs^ e) {
//add sender name
String^ name = this->serialPort1->PortName;
// grab text and store in send buffer
String^ message = this->textBox2->Text;
// write to serial
if(this->serialPort1->IsOpen)
//this->_serialPort->WriteLine(String::Format("<{0}>: {1}",name,message));
this->serialPort1->WriteLine(message);
else
this->textBox2->Text="Port Not Opened";
}
//Sorry for the bad format. Must learn how to use it correctly.
void createRandom(std::string & randString, const int len)
{
static const std::string theCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i)
{
//generate a random number which not bigger that max size of the available characters, then add it to the string.
randString += theCharacters[rand() % (sizeof(theCharacters) - 1)];
}
}
createRandom(message);
this->serialPort1->WriteLine(message);

call c++ function in Java with input and output arguments

I have a c++ code which has been connected to a visual basic user interface by someone else. Here is one of the functions code that connects c++ to visual basic:
extern "C" void PASCAL EXPORT RCS( stAct* act,stResourceDirectory* resDir, stCalendar* calendar, short numOfAct, short numOfRes, short numOfCal, int nDataDate )
{
Network network;
short id;
Activity* p_act;
node<Activity>* p_node;
// Setting
network.create_calendars (calendar, numOfCal);
network.set_data_date (nDataDate);
set_activity(network, act, numOfAct );
// only for id, duration, and description
set_resource(network, act, resDir, numOfAct, numOfRes);
// create resource profile and add required resource for every activity
network.CPM ();
p_node = network.get_network_head_p();
while (p_node != NULL ) {
p_act = p_node->refer_data();
id = p_act->get_ID ();
act[id].TF_in_CPM = p_act->get_TF_min ();
act[id].FF_in_CPM = p_act->get_FF();
act[id].EST_in_CPM = p_act->get_EST ();
act[id].EFT_in_CPM = p_act->get_EFT ();
act[id].LST_in_CPM = p_act->get_LST ();
act[id].LFT_in_CPM = p_act->get_LFT ();
p_node = p_node->get_link();
}
network.RCS();
p_node = network.get_network_head_p();
while (p_node != NULL ) {
p_act = p_node->refer_data();
id = p_act->get_ID ();
act[id].TF_in_RCS = p_act->get_TF_min ();
act[id].FF_in_RCS = p_act->get_FF();
act[id].EST_in_RCS = p_act->get_EST ();
act[id].EFT_in_RCS = p_act->get_EFT ();
act[id].LST_in_RCS = p_act->get_LST ();
act[id].LFT_in_RCS = p_act->get_LFT ();
p_node = p_node->get_link();
}
}
I want to replace the visual basic part with a Java GUI and it seems confusing for me to write the connection code. Is there anyone who can help me call three c++ functions with passing arguments to the native method and receiving results from it, by JNA/ SWIG/ Runtime or any other methods you think it would work easier and better?
Here is an instructional example to help get you started. In this snippet, Java2Win64 is the DLL that contains the native code to execute. Function functionMaryam() takes 1 param as int and returns an int. Easy to expand for any data type.
public class JnaExampleMaryam {
// ------------------------------------------
// Java2Win.class
// ------------------------------------------
public interface Java2Win extends Library {
Java2Win call = (Java2Win) Native.loadLibrary("Java2Win64", Java2Win.class);
int functionMaryam(int i);
}
// ------------------------------------------
// ------------------------------------------
// Test
// ------------------------------------------
public static void main(final String args[]) throws Exception {
final File file = new File("rootToDLL", "Java2Win64.dll");
LibraryLoader.loadLibrary(file);
int result = Java2Win.call.functionMaryam(42);
}
// ------------------------------------------