Using forms in a C++ DLL just to note. I'd thought this would be important as I need it to have the same variables as the Application has (which may or may not be different)
Starting my form I have to do this:
Form1 ^ ThisForm = gcnew Form1;
Application::Run(ThisForm);
Which is basic nothing to difficult. I get my form working fine upon use. Now I want to create a thread through Form1 (ThisForm). They are defined here:
public:
VOID WINAPI MainThread2();
And all it does is set the label within this to the current time:
VOID Form1::MainThread2()
{
while (true)
{
Beep(400, 100);
time_t CurrentTime = time(0);
struct tm* TimeStruct = localtime(&CurrentTime);
string str = to_string(TimeStruct->tm_hour) + ":" + to_string(TimeStruct->tm_min) + ":" + to_string(TimeStruct->tm_sec);
String^ timestring = gcnew String(str.c_str());
this->label1->Text = "hello";
}
}
But obviously I can't create a thread with this:
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThisForm->MainThread2, NULL, NULL, NULL);
Due to this error:
error C2440: 'type cast': cannot convert from 'overloaded-function' to 'LPTHREAD_START_ROUTINE'
How would I manage to start a thread through ThisForm
I recommend that you avoid the unmanaged thread APIs, and use the managed ones. This will let you use instance methods of managed classes, rather than just static C++ methods.
MSDN References:
Thread class
Thread constructor
If you really do want to use the unmanaged APIs, you need to make your thread method a static or global method (not instance, as you have it now). I don't remember off the top of my head if it's allowed to be a static method of a managed class; you may need to have it be a global method to make this work. (A static method of an unmanaged class would also work, but that doesn't buy you much.)
Related
I'm using VC++2017 to write a program to communicate with a PLC using Modbus. Ideally, I want to create a class that inherits from the MbusAsciiMasterProtocol but it's looking like that will be impossible. My current header file for it is:
#pragma once
#include "MbusAsciiMasterProtocol.hpp"
class PlcModbus
: public MbusAsciiMasterProtocol {
public:
/* Also tried without calling MbusAscii constructor and doesn't work*/
PlcModbus() : MbusAsciiMasterProtocol() {}
~PlcModbus() {}
};
and the part in the main function that uses it is
/* Doesn't work */
int dataArr[18];
PlcModbus plc;
plc.openProtocol("COM3", 19700L, 8, 1, 0);
plc.readMultipleLongInts(1, 1, dataArr, sizeof(dataArr) / sizeof(int)); // Breaks here
plc.closeProtocol();
Which throws a null pointer exception when it gets to plc.readMultipleLongInts (it successfully calls openProtocol and opens the connection). I did some digging with the debugger and found that the stack pointer after the function is called is 12 spaces away from where it was prior to the function call.
Now, if I don't inherit from MbusAsciiMasterProtocol and instead use the class directly, everything works fine.
/* Works fine */
int dataArr[18];
MbusAsciiMasterProtocol plc;
plc.openProtocol("COM3", 19700L, 8, 1, 0);
plc.readMultipleLongInts(1, 1, dataArr, sizeof(dataArr) / sizeof(int));
plc.closeProtocol();
There is no runtime error and I am able to communicate with the PLC. This makes absolutely no sense to me because up until this point I assumed that inheriting from a base class essentially gave you access to the same public and protected member functions within the base class. But this seems to imply otherwise.
I also tried to use MbusAsciiMasterProtocol as an object in PlcModbus and write wrappers around the functions I need, but that didn't work either and it gave the error "- The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention."
#pragma once
#include "MbusAsciiMasterProtocol.hpp"
class PlcModbus {
public:
PlcModbus() : myModbus(MbusAsciiMasterProtocol()) {}
~PlcModbus() {}
int openProtocol(const TCHAR *portName, long baudRate, int dataBits, int stopBits, int parity) {
return myModbus.openProtocol(portName, baudRate, dataBits, stopBits, parity);
}
int readMultipleLongInts(int slaveAddr, int startRef, int *int32Arr, int refCount) {
return myModbus.readMultipleLongInts(slaveAddr, startRef, int32Arr, refCount);
}
void closeProtocol() {
myModbus.closeProtocol();
}
public:
MbusAsciiMasterProtocol &myModbus;
};
I feel there must be something going wrong with the calls to the static library based off of that error, but why it works when I use the base class and not when I inherit from it is beyond me. Any explanation about what's going on would be extremely helpful.
Cheers.
I don't know why inheriting from MbusAsciiMasterProtocol doesn't work for you.
However in your last code example where you write wrappers around functions you have one subtle error:
MbusAsciiMasterProtocol &myModbus; creates a reference to MbusAsciiMasterProtocol object.
In the constructor you are initializing it with MbusAsciiMasterProtocol() - a temporary object thus creating a reference to a temporary. This is probably the source of the errors you are getting. Remove the reference and make the object private instead of public.
Using VC++ 2010.
I want to access a form's control from a class in another thread.. and can't figure out the best (or any) way to do this. How can I pass a reference of my form instance? Im using createthread() as opposed to the managed version, wanting to make my app compatible with XP.
I've tried passing a reference and other values in a struct through the lpParameter, but I can't seem to figure out how to declare the reference properly.
ref class SZClass {
private:
FMain ^bound_form;
int server_port;
public:
void BindForm(FMain ^bf);
void Initialize(int sp)
}
struct param_data {
public:
FMain ^form_tobind;
int port_num;
}
are giving me errors:
error C2143: syntax error : missing ';' before '^'
FMain is the name of my form class, and I have a delegate method already set up to make it multithread safe:
public:
FMain(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
void FMain::PrintConsole(std::string mzg) {
String ^Smzg = marshal_as<String^>(mzg);
if (this->textBox1->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &FMain::PrintConsole);
this->Invoke(d, gcnew array<Object^> { Smzg });
} else {
textBox1->Text += Smzg;
textBox1->SelectionStart = textBox1->TextLength;
}
}
How do I declare a reference to my form?
Or is there an easier or better way to do this?
I don't know what forms library you're using, but the general rule of thumb for your question is, "Don't."
Unless you have a peculiar GUI library, Windows UI is thread-affinitized. All access to UI elements should be done via the ui's affinitized thread. Manipulating UI state from an unaffinitized execution context should be done by marshaling the update request to the affinitized context. It should not be done directly.
I'm working on a student project. It's a network card game. The solution contains 3 projects. Client's GUI using Windows Forms so it has managed classes. Static client's library in native C++. GUI's project has reference to it thus uses 'Mixed Rules'. Server is in native C++ as well. I use RPC middleware for communication. It works only with native C++. That is why I need the static library to hide there all the details of communication on client's side.
Since the server can at any moment change its state and that should be shown in client's GUI, I use callback approach to change Windows Forms' components. And here I found a problem because I need to change private members of managed class with the help of a native object.
There are probably different ways to do that. My idea is sending a pointer to instance of managed class into instance of native class and saving it there. So later I can call from that native object public member functions of that managed class to change components.
This is from my 'Mixed Rules' GUI project:
//Native class for changing window 'Lobby'
class LobbyI : public ClientLib::Lobby {
public:
LobbyI();
~LobbyI();
//Should change window due to current Server's state
void reDraw(const CommonLogic::ServerState&);
};
// Managed class implements GUI for window 'Lobby'
// generated by Visual Studio designer
public ref class LobbyGUI : public System::Windows::Forms::Form {
//My members
ClientLib::Mediator* mediatorPtr; // Is it correct?
LobbyI* lobbyPtr; // ?
public:
LobbyGUI(void) {
InitializeComponent();
mediatorPtr = new ClientLib::Mediator(); // Is it correct?
lobbyPtr = new LobbyI(); // ?
mediatorPtr->setCallback(lobbyPtr);
}
protected:
~LobbyGUI() {
if (components) { delete components; }
delete lobbyPtr; // Is it correct?
lobbyPtr = nullptr; // ?
delete mediatorPtr; // ?
mediatorPtr = nullptr; // ?
}
private: System::Windows::Forms::Button^ buttonLogIn;
//...
This is from native static library ClientLib:
class Lobby {
public:
virtual ~Lobby();
virtual void reDraw(const CommonLogic::ServerState&) = 0;
};
class Mediator {
CommonLogic::ServerState serverState;
Lobby* lobbyPtr;
public:
Mediator();
~Mediator();
void setCallback(Lobby* ptr) { lobbyPtr = ptr; }
void reDrawLobby() { lobbyPtr->reDraw(serverState); }
};
This code builds ok. The only thing I need now is that the member function reDraw() of native derived class LobbyI is able to change the window implemented by managed class LobbyGUI. Thus getting and keeping and using pointer to it. And then I think it all will work. How to do that?
Maybe it's not the nicest implementation in general. I would be happy to read other suggestion.
I'm also doubtful about the way I used pointers to native classes inside managed class. Is it correct? It didn't work correct until I inserted ptr=nullptr; after delete ptr; in destructor.
UPDATE: Now I see redundancy in my code. Abstract class Lobby is useless. I need only to implement reDraw() function in managed class which will have obviously access to components of the window. And then pass safe pointer to native class function which expects pointer to a function as a parameter.
Finally I've solved it!! Using this article. In the following code a native object stores provided pointer to a function of managed object. So this callback function can be invoked at any time. A delegate is used as a form of type-safe function pointer. Instance of GCHandle is used to prevent the delegate from being relocated by garbage collector.
Here is simple CLR Console Application which increments and prints some integer using callback function invoked from native object. Thus we can "change private members of managed object using a native one".
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void(__stdcall *ANSWERCB)(); // define type of callback function
#pragma unmanaged
class NativeClass {
ANSWERCB cbFuncPtr = 0; // pointer to callback function
public:
void setCallback(ANSWERCB fptr) {
cbFuncPtr = fptr;
incAndPrint();
}
void incAndPrint() { cbFuncPtr(); } // invokes callback which increments and prints
};
#pragma managed
ref class ManagedClass {
public: delegate void Del();
private:
Int32 i;
NativeClass* nativePtr;
Del^ delHandle;
GCHandle gch;
public:
ManagedClass(Int32 ii) : i(ii) {
nativePtr = new NativeClass;
delHandle = gcnew Del(this, &ManagedClass::changeAndPrintInt);
gch = GCHandle::Alloc(delHandle);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(delHandle);
ANSWERCB callbackPtr = static_cast<ANSWERCB>(ip.ToPointer());
nativePtr->setCallback(callbackPtr);
}
~ManagedClass() {
delete nativePtr;
nativePtr = __nullptr;
gch.Free();
}
private:
void changeAndPrintInt() // callback function
{
Console::WriteLine(++i);
}
};
int main(array<System::String ^> ^args)
{
ManagedClass mc(1);
return 0;
}
I've subclassed my Qthread so I can implement my code in run() method. I have to pass it some parameters,
I tried it like this, so what's wrong in here?
class QMyThread :
public QThread
{
public:
QMyThread();
~QMyThread(void);
virtual void start(FILE *data, int sock, int bits);
protected:
virtual void run(FILE *data, int sock, int bits);
};
run method;
void QMyThread::run(FILE *data, int sock, int bits)
{
//do stuff
}
start the thread:
QMyThread *thread;
thread->start(datafile, sockint, bitsint);
first it says the thread might not be initialized and then it crashes in the start() method with SIGSEGV error. Anyone can help me?
You shouldn't be subclassing the QThread class as this is no longer the recommended way of using QThread.
For more information http://qt-project.org/doc/qt-4.8/qthread.html
To answer your question, couldn't you just make those parameters members of your class and assign their values through setters or its contructor?
You should do this instead:
QMyThread thread;
thread.start(...)
You created a pointer to a thread and did not new it. I frankly see no reason for a pointer here, you can just create a normal variable and call a method on it.
If you do want a pointer, then use std::unique_ptr in C++11 or boost::unique_ptr
std::unique_ptr<QMyThread> thread;
thread->start(...);
EDIT:
You should really just create a QThread * thread = new QThread(this); as per the documentation.
How about using the QMetaObject class to pass the parameters to worker class. You can try like this:
QMetaObject::invokeMethod(worker, "methodName", Q_ARG(QString, "ParameterQStringValue");
Note this method will work if methodName is a slot and you use the new way of creating threads: https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
You can specify different parameters using Q_ARG macro up to 9 (http://doc.qt.io/qt-5/qmetaobject.html#details). If you need more parameters, then I suggest you to create the QVector with a structure and pass it to QMetaObject::invokeMethod as the parameter.
I'm trying to encapsulate some older win32 code in a C++/CLI ref class to make it better accessible from .NET code. This class needs to start a Win32 thread and pass a pointer to the class as a thread parameter. The code looks something like this:
ref class MmePlayer
{
int StartPlayback()
{
hPlayThread = CreateThread(NULL, 0, PlayThread, this, 0, &PlayThreadId);
}
};
static DWORD WINAPI PlayThread(LPVOID pThreadParam)
{
// Get a pointer to the object that started the thread
MmePlayer^ Me = pThreadParam;
}
The thread really needs to be a Win32 thread because it receives messages from the MME subsystem. I've tried wrapping the PlayThread function pointer in an interior_ptr, but the compiler wouldn't allow that.
Also, I've tried to make the thread function a class method, but the compiler does not allow the _stdcall modifier on ref class methods.
Do you know of a way to handle this?
Managed classes are passed around using 'handles' instead of references. You can't treat a handle to a managed class like a pointer. What you're going to want to do is create a native helper class that holds a handle to the managed class. Then you pass a pointer to the native helper into the thread start function. Like this:
#include <msclr/auto_gcroot.h>
using msclr::auto_gcroot;
ref class MmePlayer;
class MmeHelper
{
auto_gcroot<MmePlayer^> myPlayer;
};
ref class MmePlayer
{
int StartPlayback()
{
myHelper = new MmeHelper();
myHelper->myPlayer = this;
hPlayThread = CreateThread(NULL, 0, PlayThread, myHelper, 0, &PlayThreadId);
}
MmeHelper * myHelper;
};
static DWORD WINAPI PlayThread(LPVOID pThreadParam)
{
// Get a pointer to the object that started the thread
MmeHelper* helper = pThreadParam;
}