So we are working on new app for Windows Store and we're utilizing DirectX on C++/CX part of app and C# on other. As we needed some sort of communication, we created interface in shared library (C#) and class that implements it on C# side of the project. We then pass instance of that class to the C++. When C++ need to communicate with c#, it calls methods from shared interface and c# executes what was implemented in the class.
The problem arises when C++ calls methods from another thread than then object was passed on to it. Error:
The application called an interface that was marshalled for a different thread.
Here's how it works:
C# instance of shared interface (some class)
C# -> C++ \/ passed in parameter of public C++ method
C++ saves to variable
C++ creates new thread
C++ calls instance->SayHello();
C# exception
Shared interface: (C#)
public interface IUserMessageService
{
void WriteMessage(string message, MessageTypes type);
}
Implementation: (C#)
public sealed class UserMessageService : IUserMessageService
{ ... }
Assign method (C++)
void AssignUserMessageService(...::IUserMessageService ^service) { m_service = service; }
I then call AssignUserMessageService with instance of UserMessageService from UI thread. Error occurs when I try to access data passed by C++ when calling WriteMessage in another thread.
Is there any other way to pass instance or call method?
The problem was that I was using CoreApplication.MainWindow.CoreWindow.Dispatcher instead of Window.Current.Dispatcher
Related
I have 2 components:
- .Net Core Application running on Ubuntu OS.
- C++ shared library (.so)
Now I want C++ component to be able to call .Net Core method, either passing interface to C++ component which will use this interface to callback method implementation or passing method as a parameter to C++ component.
High-level example what I am trying to achieve:
C# component :
public interface IDevice
{
void OnDataAvailable(string data);
}
public class Device: IDevice
{
[DllImport("sampleCPPLibrary.so")]
private static extern int SetReceiver(IDevice receiver);
public void OnDataAvailable(string data)
{
Console.WriteLine(data);
}
public void Initialize()
{
SetReceiver(IDevice(this))
}
}
C++ component:
extern "C" {
void SetReceiver(IReceiver * receiver)
{
receiver->OnDataAvailable(10);
}
}
Basically, what I am trying to do is just to pass some kind of "callback" to C++ component and call this "callback" when some event occurs in C++ component.
See See this issue from comments I constructed code where C# calls C and gives it callback delegate. Thus from C then it calls C#, and passes additional int type argument. See comments here from endurox project, and attached c-callback.tar.gz for working example.
Title explains. I have native C++ dlls that I'm writing C++/CLI wrappers for, which will in turn will be imported in C# as reference.
The problem is that in C# I don't see the classes I have in wrapper (imported from DLL).
What keywords should I use and HOW to re-declare my native C++ objects to become visible in C#?
Ok, tutorial. You have a C++ class NativeClass that you want to expose to C#.
class NativeClass {
public:
void Method();
};
1) Create a C++/CLI project. Link to your C++ library and headers.
2) Create a wrapper class that exposes the methods you want. Example:
#include "NativeClass.h"
public ref class NativeClassWrapper {
NativeClass* m_nativeClass;
public:
NativeClassWrapper() { m_nativeClass = new NativeClass(); }
~NativeClassWrapper() { this->!NativeClassWrapper(); }
!NativeClassWrapper() { delete m_nativeClass; }
void Method() {
m_nativeClass->Method();
}
};
3) Add a reference to your C++/CLI project in your C# project.
4) Use the wrapper type within a using statement:
using (var nativeObject = new NativeClassWrapper()) {
nativeObject.Method();
}
The using statement ensures Dispose() is called, which immediately runs the destructor and destroys the native object. You will otherwise have memory leaks and probably will die horribly (not you, the program). Note : The Dispose() method is magically created for you.
Trying to use a COM visible .NET class via other .NET application and get exception:
Message: The object's type must be
__ComObject or derived from __ComObject.
Parameter name: o
Stack Trace: at
System.Runtime.InteropServices.Marshal.ReleaseComObject(Object
o)
The class looks as follows:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IViewer : IComInteropDefinedInterface
{
}
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[Guid("[some guid]")]
public class MyViewer : UserControl, IViewer
{
//IViewer implementation
}
I register the component with:
regasm [Assembly Path] /tlb /codebase
The client application, which is also in .NET instantiates successfully the given class, but when he callsMarshal.ReleaseComObject() it gets the exception described above.
Any idea for solving this problem?
EDIT:
Unfortunately I can't provide the client application code for instantiating my object. However I know the client is using the same method to instantiate real COM objects.
I got this problem recently, when reimplementing a native COM to managed code.
The solution was to ask if the object is a native COM with Marshal.IsComObject, only native COMs must be release with Marshal.ReleaseComObject.
This is code:
if (Marshal.IsComObject(comObject))
{
Marshal.ReleaseComObject(comObject);
}
comObject = null;
Important: you have to be sure, no use that object after been Released.
For a more detailed explanation read this post: http://blogs.msdn.com/b/visualstudio/archive/2010/03/01/marshal-releasecomobject-considered-dangerous.aspx
But how are you creating the class instance? Simply using the expression new MyViewer() doesn't create a COM object. Instead it creates a plain old .Net object which cannot be used with the ReleaseComObject method.
Based on your sample code, in particular the line about MyViewer having an implementation, it doesn't sound like you're dealing with a COM object. Instead it looks like you have a managed object which implements a COM interface.
In order to use the ReleaseComObject you'd need to actually have a COM / RCW object.
My guess would be that you are actually not using COM but simply use a referenced .NET class. If your project contains code like
MyViewer viewer = new MyViewer();
and you have added the library containing MyViewer not as a COM reference, you are actually not using COM.
I would rather try:
if (comObject != null)
{
if (System.Runtime.InteropServices.Marshal.IsComObject(comObject))
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(comObject);
}
comObject= null;
}
I have a VB6 project(windows application) and I have to redevelop a module in the existing VB6 project in C#.net.
The module that I develop in C#.net should be a dll and should contain some windows forms. I was able to successfully call a c# console applicaiton dll from my vb6 project but I am facing issues when i try to call a C# class library with winforms from my VB6 project.
This is what I have done for my Proof Of Concept - This is a class file in my C#.net class library project.
namespace TestDll
{
public interface IClass1
{
void DisplayMessage();
}
public class Class1:IClass1
{
void IClass1.DisplayMessage()
{
MessageBox.Show ("Displyaing message");
}
}
}
I have a form in the same nemspace and I plan to instantiate Class1 and use its object on the page_load event of the C# winform.
In my VB6 project I want to display the form I have in my C#.net dll. I am calling it by this code -
Private Declare Sub DislayMessage Lib "TestDll.dll" ()
Private Sub Command1_Click() //On button click event of the VB6 windows form
DislayMessage
End Sub
I get an error - "Can't find a DLL entry point in DisplayMessage in TestDll.dll"
I am not sure how to solve this error. I am even skeptical if this is the way a C#.net dll which contains some winforms should be called from a VB6.0 windows applicaiton.
Should I instantiate Class1 in my VB6 code? How do I resolve this error?
Is my approach correct? Are there better ways to do this?
TIA.
You have to make your class COM-Visible. Here's how I would change your code:
namespace TestDll
{
[Guid("FB8AB9B9-6986-4130-BD74-4439776D1A3D")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface IClass1
{
[DispId(50)]
void DisplayMessage();
}
[Guid("74201338-6927-421d-A095-3BE4FD1EF0B4")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[ProgId("TestDll.Class1")]
public class Class1:IClass1
{
void IClass1.DisplayMessage()
{
MessageBox.Show ("Displyaing message");
}
}
}
Note the [DispId(50)]. You want to specify the dispatch ID for your COM-visible methods, properties, and events. If you don't, the compiler will do it for you and you may end up breaking compatibility every time you compile. The number doesn't matter so much as it doesn't change between compiles.
You might want to check out Building COM Objects in C#. It's a pretty good getting started tutorial.
Some highlights:
Exposing the VC# objects to the COM
world requires the following …
* The class must be public
* Properties, methods, and events must be public.
* Properties and methods must be declared on the class interface.
* Events must be declared in the event interface.
Every Interface needs a GUID property
set before the interface name. To
generate the unique Guid , use the
guidgen.exe utility and select the
Registry Format.
The only way to do it is to expose your C# class as a COM object (also called a CCW - COM Callable Wrapper), and create an instance of that COM object in your VB6 code.
This should help you get started:
http://www.bing.com/search?q=C%23+CCW&go=&form=QBRE&qs=n
There some excellent help on msdn here:
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/com-interop/
I'm trying to get access to certain parts of my application through COM, mainly because I need a Delphi application to be able to invoke certain services on the .NET application.
I've managed to expose some methods via COM inheriting from ServicedComponent class and its working fine.
Now I need to be able to raise events to the client so I can alert him when certain things occur. I currently have something like this:
public interface IEvents
{
void OnMessage();
}
[EventClass]
[ComVisible(true)]
public class MyEventsClass : ServicedComponent, IEvents
{
public void OnMessage()
{
}
}
but when I import the TypeLibrary from Delphi I get this:
IEvents = interface(IDispatch)
['{E7605303-F968-3509-829B-BF70084053C4}']
procedure OnMessage; safecall;
end;
IEventsDisp = dispinterface
['{E7605303-F968-3509-829B-BF70084053C4}']
procedure OnMessage; dispid 1610743808;
end;
which I don't really know how to use. I was expecting an IUnknown interface that I can implement and provide to the service through a MyService.Register(IEvents events)...
I think I'm completely lost here... Any advice or reference about how to properly implement COM+ events with .NET?
I'm still unsure of what exactly is the use for EventClass by I've discovered you don't need to use it. I simply have declared this:
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyEventIface
{
}
And with that the interface is exported as an IUnknown interface to Delphi.
Then you define a method on your ServicedComponent class which a connect signature like this:
public void Connect(IMyEventIface eventHandler)
{
mEvents.Add(eventHandler);
}
which left you to manually handle the invoke of each client event handler but is the only way I've found.