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.
Related
I am working on mixed application, using both managed & native codes
I want to call a function deployed in a native class from Main() function located in Program.cpp which is managed class.
i tried using std::thread but failed with /cli
i tried to use Managed System::Threading::Thread but failed because i need to call a native function in a native class.
So how i can handle thing without using any third-party?
If you start from a native project you need to do the following steps:
Select project properties and change the option "No Common Language Runtime Support" to "Common Language Runtime Support /clr".
Open the "Property Manager" from "View" menu / "Other Windows" and add the property sheet "C++ Common Language Runtime Support" to the needed configuration (eg.: Debug | Win32) on my system this sheet is under "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140". I use the "Microsoft.Cpp.ManagedExtensions.props" file.
You need to remove std::thread completely.
headerish:
#pragma once
#include<stddef.h>
using namespace System;
using namespace System::Threading;
namespace FooSpace
{
// Native stuff
public class Native
{
public:
static void Foo() { }
void Bar() {
}
};
// Managed stuff
public ref class Managed
{
private:
Native* m_Native;
public:
Managed()
{
m_Native = new Native();
}
~Managed()
{
if (NULL != m_Native)
{
delete m_Native;
m_Native = NULL;
}
}
void Bar()
{
m_Native->Bar();
}
static void ThreadCall(Object^ o)
{
auto me = (Managed^)o;
me->Bar(); // Call a method of an instance of the native class
Native::Foo(); // Call a static method of the Native class
}
void StartThread()
{
auto t = gcnew Thread(gcnew ParameterizedThreadStart(ThreadCall));
t->Start(this);
t->Join();
}
};
}
soure file:
#include "stdafx.h"
#include "CppCli_Native.h"
using namespace FooSpace;
int main()
{
Native::Foo(); // call native static method
auto native = new Native(); // create native instance
native->Bar(); // call native method
auto managed = gcnew Managed();
managed->Bar(); // This will call bar
managed->StartThread(); // This will start a thread
delete managed;
Console::ReadLine();
return 0;
}
Edit: It turns out that you don't need to use IntPtr to store native class.
I find this answer also useful, it also gives us a fast introduction to c++-cli syntax.
Is there a built-in way to allow a managed ref-class to implement and expose a COM inerface that is safely callable from native code?
Looking at the C# side, this is easily done by decorating the target interface with the proper COM-interop attributes, for example:
Native Interface
interface ISampleGrabberCB: public IUnknown
{
virtual STDMETHODIMP SampleCB( double SampleTime, IMediaSample *pSample ) = 0;
virtual STDMETHODIMP BufferCB( double SampleTime, BYTE *pBuffer, long BufferLen ) = 0;
};
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,
{ 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
Managed Equivalent Interface
[Guid("0579154A-2B53-4994-B0D0-E773148EFF85")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
public interface ISampleGrabberCB {
int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
int SampleCB(double SampleTime, IMediaSample pSample);
}
Once this declaration is done, through the magic of P-Invoke you can do something like this:
public class FooClass : ISampleGrabberCB {
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {
Console.WriteLine("BufferCB called");
}
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) {
Console.WriteLine("SampleCB called");
}
public void SomeMethod(IBaseFilter aDirectShowFilter) {
ISampleGrabber sampleGrabber = (ISampleGrabber)aDirectShowFilter;
// By the magic of PInvoke, this is possible and works!
// ISampleGrabber->SetCallback() is expecting an ISampleGrabberCB* COM interface
// After the following line, native code is able to callback safely
// into our managed code
sampleGrabber.SetCallback(this, 0);
}
}
Is there a way to mimic this behavior on C++/CLI?
Evidently, the Interop plumbing to make this possible exists as it is used by C#. Furthermore, the compiler could generate the necessary managed interface from inspecting the available native interfaces (I still think we would need to provide the relevant Guids, as this is not an attribute within the native interface)
I just got curious about this topic and played around and I found out some minor differences:
I have IVI-COM class library on my PC, and always wanted to try to interface some of them, although the IVI also has .Net interfaces so it does not make too much sense...
I started with C#, where we get good IntelliSense support. I have added the necessary references and added a class to my project. With the object browser we can select an interface.
public class MyDmm : IIviDmmMultiPoint
{
}
After that just use IntelliSense (Ctrl-.) to add the ‘using’ statement and let them make the necessary properties and methods for us.
using Ivi.Dmm.Interop;
///...
public int Count
{
get
{
throw new NotImplementedException();
}
///...
So now we need the C++-CLI dialect :) Which is as follows:
using namespace IviDmmLib;
///...
public ref class Dmm : IIviDmmMultiPoint
{
Note that the name used by the using statement is different, we can obtain this by selecting the reference at the Solution Explorer and check the name shown at the ‘Properties’ below.
I did not fully complete the experiment but I saw that the COM library was x64 bit, so we may compile the project for the same.
Further interesting readings:
Windows Runtime C++ Template Library
Please, give me feedback if you find some more differences, so we can put them here too.
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.)
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'm trying to write a bit of code (just for home use) that uses UPnP for NAT traversal, using C# 4 and Microsoft's COM-based NAT traversal API (Hnetcfg.dll).
Unfortunately (or perhaps fortunately) the last time I had to do COM interop in .NET was sometime around the last ice age, and I seem to be fundamentally confused about C#'s use of dynamic types for interop and how to write a callback (so that the COM server calls my managed code).
Here's an exciting few lines of code:
// Referencing COM NATUPNPLib ("NATUPnP 1.0 Type Library")
using System;
using NATUPNPLib;
class NATUPnPExample
{
public delegate void NewNumberOfEntriesDelegate(int lNewNumberOfEntries);
public static void NewNumberOfEntries(int lNewNumberOfEntries)
{
Console.WriteLine("New number of entries: {0}", lNewNumberOfEntries);
}
public static void Main(string[] args)
{
UPnPNAT nat = new UPnPNAT();
NewNumberOfEntriesDelegate numberOfEntriesCallback = NewNumberOfEntries;
nat.NATEventManager.NumberOfEntriesCallback = numberOfEntriesCallback;
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
In the above code, the Add and Remove calls work absolutely fine. Terrific.
The trouble is, I would also like to know when the number of port mapping entries have changed, and to do so I need to register a callback interface (INATEventManager::put_NumberOfEntriesCallback), which must support the INATNumberOfEntriesCallback or IDispatch interfaces. VS2012's object browser describes INATEventManager::put_NumberOfEntriesCallback thusly:
dynamic NumberOfEntriesCallback { set; }
Right, so I was under the impression that in C# 4 I shouldn't have to decorate anything with fancy attributes and that I can register my callback simply by jamming a delegate into INATEventManager::put_NumberOfEntriesCallback in a vulgar manner and leaving .NET to worry about IDispatch and clear up the mess; but it appears that I'm terribly wrong.
So, er... What should I do to ensure my NewNumberOfEntries method is called?
I'm also slightly concerned that I can write nat.NATEventManager.NumberOfEntriesCallback = 1; or nat.NATEventManager.NumberOfEntriesCallback = "Sausages"; without an exception being thrown.
It seems that I was able to make it work. Two options - with a custom interface "INATNumberOfEntriesCallback" (which does not seem to be declared in the type library btw, you need to declare it yourself) and using plain dispatch with DispId(0). The conversion to the IDispatch/IUnknown is preformed by the framework automatically. So:
Option 1.
Declare the INATNumberOfEntriesCallback and make a callback class which implements that interface (the tricky part is Guid - it comes from the "Natupnp.h" file, and does not seem to appear to be in the type library).
// declare INATNumberOfEntriesCallback interface
[ComVisible(true)]
[Guid("C83A0A74-91EE-41B6-B67A-67E0F00BBD78")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INATNumberOfEntriesCallback
{
void NewNumberOfEntries(int val);
};
// implement callback object
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class CallbackNewNumberOfEntries : INATNumberOfEntriesCallback
{
public void NewNumberOfEntries(int val)
{
Console.WriteLine("Number of entries changed: {0}", val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackNewNumberOfEntries();
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
Option 2.
Use plain dispatch. The documentation says that you can use dispid(0) and it should be called, with 4 (!) parameters (see the remarks section in docs). So basically the following construction seems to work in "dispatch" way:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class CallbackDisp
{
[DispId(0)]
public void OnChange(string updateType, object obj, object name, object val)
{
Console.WriteLine("{0}: {1} = {2}", updateType, name, val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
I had the same problem you had, and since there isn't much help on the topic your posting helped tremendously! It wouldn't let me comment on your answer because I don't have enough points or whatever but your answer is the best, but doesn't quite work how I thought it would.
nat.NATEventManager.ExternalIPAddressCallback = new CallbackDisp();
Works, using the same dispatch, and will tell you when the external IP changes. HOWEVER,
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
only reports UPnP map changes from these conditions: A.) It was added/removed by the NATUPnP instance.. In this case:
nat.StaticPortMappingCollection.Add();
OR B.) it was already mapped when the instance was created:
var nat = new UPnPNAT();
As an example, if Utorrent was running when you started your program and you you had something to block the program from exiting(Console.WriteLine();) for example.. When you exit Utorrent the callback would fire, and notify you of the map changes. Which is exactly what I wanted in the first place. However, if you re-open Utorrent, or any other app that uses UPnP it will NOT fire the callback, and will not notify you of the change.
Needless to say it has been very frustrating. If you figure it out please share! I know I can easily implement the functionality by polling the StaticPortMappingCollection at a given interval, but it seems a little 'hacky' to me.