I have a C# DLL being called from Excel VBA which I have exposed via a COM Callable Wrapper / COM Interop. I want to be able to pass any exceptions which occur in the C# code up onto the VBA client. Are there any recommended approaches to doing this ? Thanks.
It is possible to create your own exceptions that communicate HRESULT error codes back to VBA or other COM based callers. Here's an example that uses E_FAIL:
public class ComMessageException : Exception
{
public ComMessageException(string message)
:base(message)
{
HResult = unchecked((int)0x80004005);
}
}
Here is an MSDN article that describes the process.
This should give you the same VBA error support you had in VB6, it will display the error message of your choice to the user along with the HRESULT that you choose.
Years ago I have vague memories of returning error information on COM function calls. COM functions should not return exceptions. The fact that an error happened in the COM function is signalled by the return value. S_OK (0) meant success. negative numbers meant failure. You could use different negative numbers to pass basic error types, however for more specific error information, you had to implement the IErrorInfo interface on the COM object.
Having done this, Visual Basic 6 and Visual Studio 2000 handled COM errors nicely in Visual Basic, however older versions of VBA didnt.
If someone has used COM much more recently they may well be able to fill in the details, and correct where my memory has gone hazy over the years.
It strikes me that implementing a new COM wrapper code that translated exceptions into documented COM errors would not be an easy generic thing and that making a hand coded version could be done, but again, you would need to understand COM programming.
Redesigning your .NET objects so they reported error detail by calling your getlasterror() method in your object would be a sensible workaround.
Related
I'm trying to configure access, launch permissions along with set run as to one of our custom DCOM application.
I have already gone through these links
dcomcnfg functionality programmatically
and http://www.myitforum.com/articles/11/view.asp?id=9323 (downloaded c++ DCOMPerm library)
I tried the code from the first link above as is written by "longofest" but the following line of code
var value = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Ole", "DefaultAccessPermission", null);
always gives me back a null value,however when I looked into the registry entries on my machine the "DefaultAccessPermission" entry for Ole registry key does have a binary value there then why I always receive a null back, no idea.
Secondly I tried the c++ library downloaded from the second link above and tried to do a COM call to one of the methods with DLLImport attribution (for automating the launch permissions for the DCOM object) but some marshalling issue is not letting me pass in the C# types corresponding to C++ types and spitting out an exception that says PInvoke cannot return variants.
I couldn't find anything concrete after googling for several hours, any help on this account will be more than appreciated.
Never worked with C++, got very poor knowledge of this language.
Update:The null value issue is solved but I don't know how to set access permissions and set run as. I have seen in c++ code that for setting access permission the code needs a domain and username but what is the c# equivalent of that, no idea....
I used the tblimp.exe tool from Microsoft and created an interop .dll assembly out of DComPerm.dll (c++ assembly) to reference in C# code and by means of Run Time Callable Wrapper I'm calling various methods on COM objects to write my C# program, so no need of DLLImport or MarshalAs attribution since RCW will take care of all the marshalling and unmarshalling issues.
I've been on a quest for a while now to pass the PCM of an MP3 from W8.1/WP8.1 to Unity3D and I believe I'm getting close. I was referred to this project which works absolutely fine but, of course, it's in VB.NET so it can't be used with Unity. VB and C# are fairly similar so I set out to translate it. You can see my translation at this pastebin.
The problem occurs on line 97. The app simply exits with absolutely no indication of what went wrong. Calling any non-inherited function on the interfaces IMFSample and IMFMediaType has the same effect.
A friend suggested getting the HRESULTs from these functions to see if anything shows up. Google shows getting HRESULTs from COM interops in C# is.. hard. I experimented by changing IMFSample.GetSampleFlags to
int GetSampleFlags(out int pRetVal);
And that returned "The requested attribute was not found. (Exception from HRESULT: 0xC00D36E6)" and I'm not really sure what to do with that information...
So, I humbly ask you all... just... just what? What do I do from here?
--- SOLUTION ---
So as it turns out the solution was a little dumber than I expected.
I did not know this, but apparently COM interfaces that inherit from other COM interfaces have to include ALL of the methods from the parent COMs. Otherwise windows, it seems, throws a hissy fit.
That was it... it was my own laziness in the first place that killed me.
I call a DLL in ASP.NET a DLL that is written in C++.
When running it into IIS 7, The pool (w3wp.exe) crash and the "just in time debugging window" open.
I do many tracing and I found that crash happen when calling any function (in the unmanaged DLLs) that have a "out string" parameter (or return a string value).
I saw on the web than many people have this problem with their DLL (C, Delphi, VB6). But no answer. so I call experts!
How can I call these functions so IIS 7 process it without error ?
cas sakal
You should use StringBuilder for interop string output parameters:
[MarshalAs(UnmanagedType.LPStr)] StringBuilder myString
It may not be possible. COM provides an interface specification, but not a guarantee that the caller be able to use the interface correctly. Unless the COM object exposes methods which are automatically marshalable by the COM subsystem (eg: automation compatible), you may not be able to use them. It's easily possible to write a C++ COM object which cannot be directly accessed out-of-process, or by any language other than C++.
You may be able to write some custom marshaling code to make it work, but I wouldn't assume it will work directly. If the types are simple/direct enough, there may be some built-in marshal attributes to make it work; I don't have a lot of knowledge in this area, though, so hopefully other people can help out.
Can anyone provide some information on how to programmatically translate HRESULT (http://en.wikipedia.org/wiki/HRESULT) values to a human-readable message?
I know that the utility ERR.EXE does this, but my app needs to display some meaningful message to my users rather than a cryptic 0x800A03EC.
There's no built-in support for generating messages from an HRESULT with that value. The COM component needs to implement that itself, using the IErrorInfo interface.
The CLR interop support built into .NET already does that automatically, you should never need to help. It automatically throws an appropriate exception when it sees a COM interface method return a failure code. The Message property is initialized from IErrorInfo. If you get nothing decent as a message then the COM server just doesn't supply it.
Which is likely for 0x800a03ec, it is a grab-bag low-level Excel error with many error causes. You can find plenty of hits for it by googling "excel error 1004".
Have you tried FormatMessage function? You can use it from C# using PInvoke mechanism.
I'm about to start writing a .Net component which will be called from a VB COM+ service (the new component is a DLL which calls out to a webservice and returns based on the response). I'm not sure how to handle error conditions that might occur in the .Net code in the calling VB.
The two types of errors I'm worried about are:
exceptions that I might like to throw if a precondition is not met (e.g. the start date supplied as a parameter is less than 3 months after the end date supplied as a parameter; I might want to throw a StartDateNotValidException)
exceptions that are likely to happen as part of the webservice call (time out, 404 etc).
I'd like to return some specific feedback to the user and/or log some information to a log if either of these occur. I'd thought about returning Int return codes from the .Net code and avoiding Exceptions, but it's possible that the calling VB code may eventually be migrated to .Net, so I'd like to use Exceptions if possible.
I read on MSDN that COM Interop will automatically convert standard library exceptions to HRESULTs; has anyone had any experience using this? Could this be used to translate custom .Net exceptions to error conditions that I can handle in VB?
Thanks,
Nick
I am sure I have seen it done before, but it was in my previous job so I can't check the details. I think we inherited our exception classes from COMException and set the correct ErrorCode (which should be translated as HResult in unmanaged code). This is quite nice, because you can use HResult in unmanaged code as well as properly handle typed exception in managed client.
Please let me know if it actually works.
I ended up using the following method:
have a big Dictionary
that maps our application-specific
VB error codes to our
application-specific C# custom
exceptions
write a method that converts C# exceptions to VB error codes (and
vice-versa)
return an array of strings from the methods containing any business
exceptions that occurred in the
method call (there are only currently two of these)
The reason for doing this is that it was going to be too cumbersome to adapt our exception tree to extend COMException (more cumbersome than the above anyways). So, I never tried out inheriting from COMException and checking whether the ErrorCode got correctly converted to an HResult.
Thanks for the suggestion though, and apologies for not trying it out.