Using VC++ 6.0 COM DLL from Threads C# - 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.

Related

Jni C++ findclass function return null

I found a problem with jni about C calling Java code.
Environment WIN10 JDK1.8
Currently I need C++ code to call Java code. At first I wrote a demothat was successful. Code show as below:
public class Sample2 {
public String name;
public static String sayHello(String name) {
return "Hello, " + name + "!";
}
public String sayHello() {
return "Hello, " + name + "!";
}
}
Some of the C++ code is as follows:
int main(){
printf("hello world");
JavaVMOption options[3];
JNIEnv* env;
JavaVM* jvm;
JavaVMInitArgs vm_args;
long status;
jclass cls;
jmethodID mid;
jfieldID fid;
jobject obj;
char opt1[] = "-Djava.compiler=NONE";
char opt2[] = "-Djava.class.path=.";
char opt3[] = "-verbose:NONE";
options[0].optionString = opt1; options[0].extraInfo = NULL;
options[1].optionString = opt2; options[1].extraInfo = NULL;
options[2].optionString = opt3; options[2].extraInfo = NULL;
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
// 启动虚拟机
status = JNI_CreateJavaVM(&jvm, (void**)& env, &vm_args);
if (status != JNI_ERR){
// 先获得class对象
cls = env->FindClass("Sample2");
}
}
I used Eclipse to compile the Java code into a .class file, copy the .class file into my C++ project, the above DEMO C++ call Java function is successful, and the findclass function returns to normal.
Because I have to introduce a third-party JAR package org.eclipse.paho.client.mqttv3-1.2.0.jar in my own Java, based on the above example, I modified the Java code in DEMO, but when I want to reference the JAR package function, And then run successfully in Eclipse, when I copy the .class file to the C++ project. JNI_CreateJavaVM in the C++ code is returned successfully, but FINDCLASS always returns null, I don't know why. I have not changed the other parts code.
Some Java code:
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
public class Sample2 {
public String name;
static MqttAsyncClient mqttClient = null;
static String username = "xxx";
static String password = "xxx";
static String broker = "xxx";
public static void main(String[] args) throws InterruptedException {
System.out.print("hello");
}
public static void start() {
String clientId = "mqttserver" + String.valueOf(System.currentTimeMillis());
try {
mqttClient = new MqttAsyncClient(broker, clientId, new MemoryPersistence());
} catch (Exception me) {
me.printStackTrace();
}
}
When in start function is added
mqttClient = new MqttAsyncClient(broker, clientId, new MemoryPersistence()); After the code, there will be problems
Take a look here
char opt1[] = "-Djava.compiler=NONE";
char opt2[] = "-Djava.class.path=.";
char opt3[] = "-verbose:NONE";
options[0].optionString = opt1; options[0].extraInfo = NULL;
options[1].optionString = opt2; options[1].extraInfo = NULL;
options[2].optionString = opt3; options[2].extraInfo = NULL;
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
You are passing three options (array of options with three options defined) but then, you say something like this
vm_args.nOptions = 1;
which means you are passing just one option. It means your options
char opt2[] = "-Djava.class.path=.";
char opt3[] = "-verbose:NONE";
are not even read. You have to change your code to
vm_args.nOptions = 3;
Also, make sure to put on java.class.path all the JARs, folders, where classes required by your code are.

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();
}

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

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));
}
}
}
}

WaitOne() timeout parameter lost?

why System.Threading.WaitHandle.WaitOne() hasn't overload for the timeout parameters as available in standard .NET implementation: http://msdn.microsoft.com/en-us/library/cc189907(v=vs.110).aspx
It's very useful in working threads when, during thread sleep, thread is requested to stop from Main UI thread.. Other ways to implement it?
Example:
public void StartBatteryAnimation()
{
whStopThread = new ManualResetEvent(false);
batteryAnimationThread = new Thread(new ThreadStart(BatteryAnimation_Callback));
batteryAnimationThread.Start();
}
public void StopBatteryAnimation()
{
whStopThread.Set();
batteryAnimationThread.Join();
batteryAnimationThread = null;
whStopThread.Dispose();
whStopThread = null;
}
public void BatteryAnimation_Callback()
{
bool exitResult = false;
while (true)
{
// Do some stuff
exitResult = whStopThread.WaitOne(WAIT_INTERVALL);
if (exitResult) break;
}
}
Thanks Frank for your (1000th!!) reply.
So my custom implementation for WaitHandle.WaitOne(int Timeout) has been:
private Thread batteryAnimationThread = null;
private Semaphore batteryAnimationSemaphore = null;
public void StartBatteryAnimation()
{
batteryAnimationSemaphore = new Semaphore(1);
batteryAnimationSemaphore.Acquire();
batteryAnimationThread = new Thread(new ThreadStart(BatteryAnimation_Callback));
batteryAnimationThread.Start();
}
public void StopBatteryAnimation()
{
batteryAnimationSemaphore.Release();
batteryAnimationThread.Join();
batteryAnimationThread = null;
batteryAnimationSemaphore = null;
}
public void BatteryAnimation_Callback()
{
bool stopThread = false;
try
{
while (true)
{
// Do some stuff..
stopThread = batteryAnimationSemaphore.TryAcquire(1, BATTERY_ANIMATION_INTERVALL, Java.Util.Concurrent.TimeUnit.MILLISECONDS);
if (stopThread) break;
}
catch (Exception ex)
{
}
batteryAnimationSemaphore.Release();
}
Is this the right way for?
Thanks
This one hasn't been implemented yet. You may use semaphore.tryAcquire instead.
Background: Due to its design, dot42 supports the entire Android API (C# classes are proxies and generated from the android.jar). But is supports only part of the .NET API because the .NET classes are handcrafted on top of the Android/Java API.
Related question: Java Equivalent of .NET's ManualResetEvent and WaitHandle
UPDATE
We released the API under Apache License 2.0 so anyone may contribute now. I also logged an issue.

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);
}
// ------------------------------------------