I hope the explanation makes sense.
I have a line
(new Shell()).NameSpace(TargetDirectory).CopyHere(SourceFile, 16 | 2048);
It works just fine when I'm calling it sequentially. Meaning I have my Main method and in that, I call the method that contains the line.
What doesn't work is calling the containing method from an event. I have a FileSystemWatcher and in it's Changed event, I call the method containing this line. Then I get
System.InvalidCastException: 'Unable to cast COM object of type 'System.__ComObject' to interface type 'Shell32.Shell'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{34936BA1-67AD-4C41-99B8-8C12DFF1E974}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).'
And here's where I'm stuck. I now that line itself works just fine so I've no idea what to repair and how.
Related
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.
I am using DirectShow's SampleGrabber to capture an image from a webcam video. Codes are writing in C# and use .NET wrappers of DirectShow's interfaces to do COM communication. The following BufferCB, first, copies image data to a local array variable, disables SampleGrabber callback, processes a received image data, and uses MessageBox to shows a result.
public int BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
{
if (Monitor.TryEnter(lockSync))
{
try
{
if ((pBuffer != IntPtr.Zero))
{
this.ImageData = new byte[bufferLen];
Marshal.Copy(pBuffer, this.ImageData, 0, bufferLen);
// Disable callback
sampleGrabber.SetCallback(null, 1);
// Process image data
var result = this.Decode(new Bitmap(this.ImageData));
if (result != null)
{
MessageBox.Show(result.ToString());
}
// Enable callback
sampleGrabber.SetCallback(this,1);
}
}
finally
{
Monitor.Exit(this.parent.lockSync);
}
}
return 0;
}
Now, if the result = null, hence the MessageBox.Show never runs, both clamping calls sampleGrabber.SetCallback() will run without any issue. Once the result != null, and the MessageBox shows up, the call sampleGrabber.SetCallback(this,1) will throw the InvalidCastException as below:
Unable to cast COM object of type 'System.__ComObject' to interface type 'DirectShowInterfaces.ISampleGrabber'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{6B652FFF-11FE-4FCE-92AD-0266B5D7C78F}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
If I stop in a VS debugger and add a watch of ((ISampleGrabber)sampleGrabber).SetCallback(sampleGrabber, 1), I will get the ArgumentException with the message of "Cannot find the method on the object instance." instead.
May someone experience the same issue can give me some advise. Thank you.
BufferCB and SampleCB calls take place on worker threads, which typically belong to MTA. Your graph initialization on the other hand typically takes place on STA thread. DirectShow API and filters volantarily ignore COM threading rules while .NET enforces thread checks an raises exception on attempts to use COM interface pointer on a wrong thread. You are hitting exactly this issue.
You don't need to reset callback and then set it back. Use SampleCB callback instead and it happens as a blocking call. Before you complete the processing the rest of the streaming is on hold.
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.
I'm consuming a com object in c#, using com-interop. I provide an event handler to the object, which it calls after doing its thing. Here's the problem. I have some sanity-check code in the handler that throws an exception if all is not well with the world:
_comObj.OnRequestCompleted += (int requestID, RequestStatus status) =>
{
if (<sanity check fails>)
throw new Exception("This is insane!!!");
...
}
The com object is apparently swallowing those exceptions, because I never see them in my app. What do I need to do to "surface" those exceptions so that I am notified when they occur?
This is not unexpected behavior if the event is raised by the COM server. Exceptions are not allowed to cross the COM divide, there is no binary interop standard for exceptions. The CLR installs a catch-all exception handler in its interop layer, the code that calls your event handler. The exception you raised is translated to an HRESULT, the standard way in which COM code reports failure. Which will be 0x80131500 for a generic Exception object.
What happens next is entirely up to the COM server, it needs to do something useful with the HRESULT it got. Not seeing it do anything it all is not terribly unexpected, function call return values are often ignored, especially so with notification style calls. You certainly won't get anything resembling a managed exception.
Work with the COM component vendor or author to work something out, if possible. Which isn't very often the case. Not much you can do beyond just logging the failure then. Call Environment.Exit() if this is a gross problem that cannot possibly be ignored. This isn't really any different from having your program terminated with an unhandled exception.
You could use the Application.Current.Dispatcher.Invoke() method, by supplying a delegate in which you throw your exception.
If you look at the standard C++ COM server implementation that's generated by all Visual Studio versions (what you get using the wizards like this: ATL Tutoral Step 5: Adding an Event), the C++ code for raising an event (named a "connection point" in COM terms) looks like this.
HRESULT Fire_MyCustomEvent()
{
...
for (int iConnection = 0; iConnection < cConnections; iConnection++)
{
CComVariant varResult;
DISPPARAMS params = { NULL, NULL, 0, 0 };
hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, ¶ms, &varResult, NULL, NULL);
}
return hr;
}
So, hr does contain an error code but in general, the COM server implementer just does
Fire_MyCustomEvent()
Because in general, there can be more than one caller. What would you do if one caller fail? Fail everyone? In the general case, nothing. See this interesting discussion here on a similar subject: Observers Should Never Throw Exceptions
That said, if you own the COM server, you can catch Invoke error, and in this example, pass EXCEPINFO as the 7th argument to invoke. It will contain the .NET Exception text "This is insane!!!".
I am creating a tool in c# to retrieve messages of a CAN-network (network in a car) using an Dll written in C/C++. This dll is usable as a COM-interface.
My c#-formclass implements one of these COM-interfaces. And other variables are instantiated using these COM-interfaces (everything works perfect).
The problem: The interface my C#-form implements has 3 abstract functions. One of these functions is called -by the dll- and i need to implement it myself. In this function i wish to retrieve a property of a form-wide variable that is of a COM-type.
The COM library is CANSUPPORTLib
The form-wide variable:
private CANSUPPORTLib.ICanIOEx devices = new CANSUPPORTLib.CanIO();
This variable is also form-wide and is retrieved via the devices-variable:
canreceiver = (CANSUPPORTLib.IDirectCAN2)devices.get_DirectDispatch(receiverLogicalChannel);
The function that is called by the dll and implemented in c#
public void Message(double dTimeStamp)
{
Console.WriteLine("!!! message ontvangen !!!" + Environment.NewLine);
try
{
CANSUPPORTLib.can_msg_tag message = new CANSUPPORTLib.can_msg_tag();
message = (CANSUPPORTLib.can_msg_tag)System.Runtime.InteropServices.Marshal.PtrToStructure(canreceiver.RawMessage, message.GetType());
for (int i = 0; i < message.data.Length; i++)
{
Console.WriteLine("byte " + i + ": " + message.data[i]);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The error rises at this line:
message = (CANSUPPORTLib.can_msg_tag)System.Runtime.InteropServices.Marshal.PtrToStructure(canreceiver.RawMessage, message.GetType());
Error:
Unable to cast COM object of type 'System.__ComObject' to interface type CANSUPPORTLib.IDirectCAN2'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{33373EFC-DB42-48C4-A719-3730B7F228B5}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
Notes:
It is possible to have a timer-clock that checks every 100ms for the message i need. The message is then retrieved in the exact same way as i do now. This timer is started when the form starts. The checking is only done when Message(double) has put a variable to true (a message arrived).
When the timer-clock is started in the Message function, i have the same error as above
Starting another thread when the form starts, is also not possible.
Is there someone with experience with COM-interop ?
When this timer
I wonder if Message is called on a thread different from the one that created the canreceiver.
Do you know the threading model of CANSUPPORTLib.CanIO? If it's apartment-threaded, you may need to marshal a reference from the main UI thread to the thread called by Message somehow.
Alternatively, assuming you can change the source code of the C++ dll, and depending on your other threading requirements and constraints, you could change it to be free-threaded, in which case an object can be simultaneously accessed from multiple threads without marshalling.