Marshal.GetActiveObject throws error from C++/CLI but not C# - c#

I am trying to get access to an running instance of an application, Rational Rhapsody, through COM. I am trying to use the C++/CLI COM calls.
From C++ calling:
rhapsody::RPApplication^ App = safe_cast<rhapsody::RPApplication^>( Marshal::GetActiveObject("Rhapsody.Application"));
Causes a COM Exception : 800401E3 (Operation Unavailable)
But, using Marshal::GetActiveObject("Word.Application") works just fine. Using gcnew rhapsody::RPApplication() works fine to make a new instance and the same code in C#:
rhapsody.RPApplication App = (rhapsody.RPApplication) Marshal.GetActiveObject("Rhapsody.Application")
works just fine.
Any ideas why it doesn't work from C++/CLI?

Is your main() routine in C++/CLI flagged with [STAThread]? It's commonly required, especially when dealing with COM objects.
[STAThread]
int main(array<System::String^>^args)
{
// code here...
}

Related

Passing a Delegate to a callback function in unmanaged code using c#

I have to register a callback function written in unmanaged code from c#. I have written the following codes:
//Declaration for c++ code
[DllImport("sdk.dll")]
public static extern void sdkSetDequeueCallback(DequeueCallback cbfunc);
//call back delegate
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DequeueCallback(OutData data);
GCHandle dequeueCallbackPinHandle;
Deque = new DequeueCallback(CallBackMethod);
{//try out
// Getting error following line (1 line) , Error : Object contains non-primitive or non-blittable data.
//dequeueCallbackPinHandle = GCHandle.Alloc(Deque, GCHandleType.Pinned);
//GC.KeepAlive(Deque);
}
SetDequeueCallback(Deque);
//Call back method in c#
public async void CallBackMethod(OutData data)
{}
The above code is working without the tryout block, but the issue is application is getting stopped after a random period of time( some times 30 mins, 1 Hr , 8 hr etc). No error detected in try..catch blocks, but getting following NullReferenceException error from the Windows Event Log(application):
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NullReferenceException. I think
this
can be the issue, but tryout codes are not working. Please help me to resolve the issue
You need to insure your 'Deque' reference is alive and not overwritten as long as the callback is being used in C++. You are responsible for holding delegate C# object alive as long as the corresponding C++ callback is used.
Better yet, just use Scapix Language Bridge, it generates C++ to C# bindings (including callbacks), completely automatically. Disclaimer: I am the author of Scapix Language Bridge.

Dealing with a 3rd party library who's function call causes heap corruptions when P/Invoking

I have created a library wrapper which invokes FlexNet Publisher. It is written in C. I am trying to P/Invoke it:
[DllImport("lmgr11.dll")]
public static extern void free_job();
Its implementation is fairly simple:
void WINAPI free_job()
{
if (jobPtr != NULL)
lc_free_job(jobPtr);
jobPtr = NULL;
}
The documentation says that lc_free_job should free a job as well as all resources. Calling lc_free_job works just fine from native code (I made an ATL object expose a wrapper to it through a COM object and I can consume this method all day long from a Visual C++ console application, so I know it must work).
However, from C#, when I try to P/Invoke this method, I get the following error which crashes my application:
Unhandled exception at 0x00007FFA39358283 (ntdll.dll) in
CerberusTestHarness.exe: 0xC0000374: A heap has been corrupted
(parameters: 0x00007FFA393AF6B0).
Why is this? Can I catch it or circumvent it in any way? I can't seem to catch the exception if I wrap the call in a try-catch because its not throwing a .NET exception. Note that I don't have the source code for lc_free_job so I can't inspect it or view its source code, unfortunately. Its written in C.
The issue was due to my C# P/Invoke code from a previous invocation. Hopefully this helps anyone else who comes across the same issue.
I had defined this P/Invoke to get an error string back from a function which returns char *:
[DllImport("lmgr11.dll")]
public static extern string errstring();
I was calling it every time something failed in my 3rd party library as above. This is not the correct way to P/Invoke a method which returns char *. Otherwise, when freeing the error from the native side, it will cause a heap corruption due to the way this string was marshaled.
It needed to be defined like this:
[DllImport("lmgr11.dll")]
public static extern IntPtr errstring();
And called as follows:
var errorMessage = Marshal.PtrToStringAnsi(errstring());

How do I add support for typed calls to a remote COM+ application

I am in the process of replacing a COM+ hosted application with a .Net variant.
The steps I took are roughly:
Generate an Interop assembly of the old dll
Create a new class in C# .Net that derives from ServicedComponent and implements the IMyClass interface from the interop.
I have annotated the class with a [Guid("...")] and a [ProgId("...")] attribute to match the class in the old dll
The end result looks like this:
[ProgId("MyComponent")]
[Guid("...")]
public class MyClass : ServicedComponent, IMyClass
{
public MyClass()
{
}
public object Open(string arg1, string arg2)
{
/* trace arguments*/
}
public object Run()
{
/* implementation here */
}
public void Close()
{
return;
}
}
This assembly is installed on a remote machine using regsvcs.exe
Now most clients use code similar to this unittest code:
Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
dynamic comInstance = Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();
This works perfectly, the .Net tracing on the remote machine tells me everything is working as it should. Other clients use code similar to this:
Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
MyClass comInstance = (MyClass)Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();
The first line is the same and seems to work fine, the rest acts weird. The VS debugger shows the lines are being executed. The remoteMachine shows that no methods are being executed.
The last call to Close(), which actually just returns, throws an exception:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Result StackTrace:
at Interop.MyComponent.IMyClass.Close()
at UnitTestProject1.UnitTest1.temp()
What have I missed in my implementation to support this last (typed) scenario?
This sounds like mismatched metadata, e.g. marshaling is different between the one that happens with the original type library and the one that happens with your server registered .NET assembly.
My guess is that the untyped case runs well because it depends solely on IDispatch, which .NET implements quite well, but the typed test fails (and I'm surprised it doesn't fail earlier) because of this mismatch.

C++ COM client releases two different objects within one call ?! 2nd Release causes access violation

I have the weirdest problem, and most likely there is something I am missing or I don't know.
I created a C# COM interface/class that for this question we'll call it: Ics_obj and Ccs_obj.
In the destructor of the object I added a trace to the output debug:
~Ccs_obj()
{
OutputDebugString("Releasing: "+this.GetHashCode()); // OutputDebugString with p/invoke
}
That I wrote a C++ class that Ics_obj is a member in that class, and the member is the com_ptr_t wrapper of Ics_obj generated in the .tlh:
class lib_exp_macro cpp_client
{
public:
cpp_client();
~cpp_client();
...
...
Ics_objPtr _csobj; // the Ics_obj* wrapped in com_ptr_t.
}
In the constructor I create an instance of Ccs_obj, and in the destructor I release it. I also added the following traces:
cpp_client::cpp_client()
{
HRESULT hr = _csobj.CreateInstance( __uuidof( Ccs_obj ) );
if(FAILED(hr)){ /* throw exception */ }
OutputDebugString("Creating client");
}
cpp_client::~cpp_client()
{
OutputDebugString("before releasing _csobj");
}
Now, I have created 2 instances of cpp_client through my code (creating them with the same thread during initialization of my application), and I get 2 traces of "Creating Client".
The problem is that during shutdown I get ACCESS VIOLATION and the traces are as follow:
before release // first object being released
Releasing: (some number X)
Releasing: (some number Y, Y != X) // <- where did that come from?
before releasing _csobj
SYSTEM CRASH HORRIBLY WITH ACCESS VIOLATION! :-(
When I debug I get ACCESS VIOLATION for accessing the v-table of the COM object.
Does anyone know why I get ACCESS VIOLATION? what am I doing wrong? I am REALLY LOST HERE! :-(
Thanks in advance!
UPDATE:
With the help of two answers (that were deleted), I understood more things, but I still have open questions...
First and the most important thing is that the 2nd release was in dllmain PROCESS_DETACH. When I moved the release code out of this context, everything was fine, but why can't I release the COM object in the PROCESS_DETACH context?!
One of the answers that were deleted said that CLR of the .Net has shutdown, therefore the 2nd release in my traces. This made a lot of sense and what lead me into moving the releasing code out of PROCESS_DETACH context, but if it is so and CLR does shutdown because the PROCESS_DETACH code, why don't I get any of the "Releasing: ..." traces if I'm not releasing the COM object (by detaching _com_ptr_t)??? Or in other words, why does CLR doesn't shutdown if I don't release the 1st object?
Thanks again for your amazing help!

How to raise Exception from C# .NET COM

How to raise Exception from a C# .NET COM. In fact I'm inside a Win32 application build using Borland Delphi 7.0 and I'm try to consume a function in .NET. Everything is working fine except the fact raising exception in C# are not re-routed to Delphi, I guess I miss some kind of method decorator. Here a piece of code:
void iLinkV2.FindLinkedClientEng(string SourceApp, string SourceClientID,
ref object ClientID, ref object Engagement)
{
throw new COMException("errClientNotFound",
(int)ExceptionsType.errClientNotFound);
ClientID = SourceClientID;
}
[ComVisible(true),
Guid("D731C821-EEA2-446E-BC5A-441DCA0477F5"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface iLinkV2
{ ...
}
You don't need to. Exceptions are not part of COM Interop specification and should not cross module boundaries. You can use status codes to indicate any errors.
Catch the exception just before method exits (in each COM interface method). Turn the result into an error code. If you use an HRESULT then you can consume it as safecall and get the Delphi compiler to re-raise an exception on the other side of the fence.

Categories