I'm using some external library though COM interface.
I have generic class for that.
Database.Connector connector = new Database.Connector();
string connectString = "srvr=nonexisthost;database=test;"; // bogus connect string
try
{
var database = connector.Connect(connectString);
}
catch (COMException ex)
{
Console.WriteLine(ex.Message);
}
Trying to build a error proof logic I intentionally provoke an exception.
And I have discovered that C# COMException contains only generic info, like:
Error HRESULT E_FAIL has been returned from a call to a COM component.
while executing samey code in PowerShell results in more detailed description:
$connector = New-Object -ComObject Database.Connector
$connectString = "srvr=nonexisthost;database=test;"
$database = $connector.Connect($connectString)
Error while executing transaction with an information base
server_addr=nonexisthost descr=11001(0x00002AF9): Host is unknown.
line=1048 file=src\DataExchangeCommon.cpp
My question is: what should I do in order to get same error info in C# (if it is possible)?
I'm not a COM Interop expert but I'll try to answer what I know and hope it will help you.
From the managed side
If the HRESULT is recognized by the runtime (CLR), the runtime automatically creates a specific managed exception for the error (e.g. FileNotFoundException). Otherwise, the runtime creates a generic COMException object which says "I don't know what this HRESULT meaning".
If the unmanaged code provides error info, you will see it in the ErrorCode property, otherwise, you will see just the HRESULT code.
You can try to search for this code (google\github) to obtain more info.
From the unmanaged side
You need to implement ISupportErrorInfo and IErrorInfo interfaces to provide more info.
So to answer your question, in C#, you can't get more info in the COMException object if this info is not provided.
For more info:
COMException, Handling COM Interop Exceptions, IErrorInfo, ISupportErrorInfo, HRESULT's mapping, Common HRESULT values
Related
I have some working Autoit code, that I would like to implement in C#.
It reads a string from a DLL as shown below.
Autoit code
Func getAxQDLink()
Local $axQdlink = ObjCreate("AxQDLink.AX_QDlink")
If IsObj($axQdlink) Then
$patInfo = $axQdlink.ContentXML
MsgBox($MB_SYSTEMMODAL, 'Test',$patInfo)
EndIf
EndFunc
I have tried this in
C# code
private void testQDOC()
{
Type axQdlinkType = Type.GetTypeFromProgID("AxQDLink.AX_QDlink");
dynamic AxQDLink = Activator.CreateInstance(axQdlinkType);
string patInfo = AxQDLink.ContentXML;
MessageBox.Show(patInfo);
}
No Exception when run, but this can be found in the watch window:
Message "Error reading type DLL. (Exception HRESULT: 0x80029C4A (TYPE_E_CANTLOADLIBRARY))"
So, any advice?
EDIT: The error seems to come in the GetTypeFromProgID method:
GenericParameterAttributes '((System.RuntimeType)axQdlinkType).GenericParameterAttributes' threw an exception of type 'System.InvalidOperationException' System.Reflection.GenericParameterAttributes {System.InvalidOperationException}
Edit2: Visual Basic can access the DLL like AutoIT does
I am working on a application which needs to communicate via COM interface with multiple CAD applications (not in the same time). I want to have nice and reusable code, but I came across problems with type casting of COM objects when I made generic application handle getter method.
What I tried so far:
This is the attempt I would like the most if it worked.
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
//Here under Dynamic View/Message there is already an error
// Message = "Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND))"
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = (TCadAppType)Marshal.GetActiveObject(cadVersion.Value);
//Following 2 lines of code are for testing purposes only, i am testing with Solidworks API
AssemblyDoc Assembly;
//The exception is thrown when I try to access some method from the Solidworks API
Assembly = (AssemblyDoc)cadApp.OpenDoc6("some parametras...");
}
Attempt using Convert class
// Another attempt using Convert class
public static TCadAppType CadApp<TCadAppType>()
{
dynamic cadApp = default(TCadAppType);
// cadVersion.Value evaluates to "SldWorks.Application"
cadApp = Marshal.GetActiveObject(cadVersion.Value);
cadApp = Convert.ChangeType(cadApp, typeof(SldWorks.SldWorks));
// Exception is thrown with the following message:
// Message = "Object must implement IConvertible."
}
I really thought that I am on the right track, since there is an article on Microsoft Docs website explaining how dynamic can help you with com interopt: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic#com-interop
Any ideas how I can do this runtime casting a keep my code as reusable as possible?
My software setup:
Win 10
Project is targeted for .NET 4.7.2
First Tests are with Solidworks 2019
Turns out that the my coding attempt 1 was valid c# code indeed.
I tried it using with Autodesk Inventor, and it works.
So the only thing left for me is to conclude that this is some bug from Solidworks and their COM interfacing.
Thank you Optional Option for your interest in the topic.
I am trying to export code from a function in C# to Delphi. I used DllExport with stdcall convention and made some tests :it works. I tested for integers and strings as params. The problem occurs when I try to use a class from Aforge library in C#. Delphi returns an error: "External Exception E0434F4D".
public class ProcessClass
{
[DllExport(CallingConvention=CallingConvention.StdCall)]
public static void ProcessImage()
{
try
{
Erosion erosion = new Erosion();
}
catch (Exception Ex)
{
}
}
}
Delphi code:
procedure ProcessImage; stdcall; external 'C:\Users\Reznicencu Bogdan\source\repos\OCR\OCR\bin\x86\Release\OCR.dll';
procedure TForm1.FormCreate(Sender: TObject);
begin
ProcessImage;
end;
The error apears at Erosion.Actually every function I use from Aforge library generates an error. I used Try/catch because I know Delphi can't catch exceptions from unmanaged code but it still doesn't work.
How can I solve this error?
The event log says: First chance exception at $767EDDC2. Exception class EExternalException with message 'External exception E0434F4D'. Process Project1.exe (9528)
The problem appears to be related to the location of the AForge DLLs. If you place those, and your class library DLL, in the same directory as your Delphi executable then the error disappears.
Perhaps there is some other way to tell AForge where to locate its DLLs. I will leave that as an exercise for the reader to investigate.
I use the following code to get metadata with Microsoft.Web.Administration.ServerManager:
var manager = new ServerManager();
var site = manager.Sites["siteName"];
var metadata = site.GetMetadata("metaKey");
Now, if "metaKey" is not there, the GetMetadata will throw a System.Runtime.InteropServices.COMException exception with the message "The request is not supported". If I first set a metadata value like this
site.SetMetadata("metaKey", "hello")
the GetMetadata("metaKey") won't throw an error but instead kindly return the value "hello". How do I check if a key exists before I attempt to retreieve it? I want to avoid a try catch if it's possible.
I've tried to dig it a little in disassembling tool. Internally it uses Microsoft.Web.Administration.Interop assembly over native API (as you've already guessed, that is why there is a COMException). Methods to work with metadata are described in IAppHostElement interface.
From it's GetMetadata method's description:
Return value:
S_OK: Indicates that the operation was successful.
ERROR_NOT_SUPPORTED: Indicates that the requested metadata is not recognized.
As you can see, there is no method to check if metadata exists, and interop throws exception in any case when returning result is not S_OK. So unfortunately I guess there is no way to know about the existence of specific metadata without calling GetMatadata method and catching exceptions.
There is a C++ COM. And it sometimes throws an exeption on SomeMethod(). C++ Com supports ISupportErrorInfo and fills IErrorInfo. How can I get the IErrorInfo.Description in c#?
This code catches the error but there is no cpp message in it.
try
{
COM.SomeMethod()
}
catch (COMException exn)
{
string ACppErrorMessage = exn.message;
outputError(ACppErrorMessage);
}
According to the documentation the Description field of IErrorInfo maps to Message of the exception object if HRESULT contains that information, otherwise it just populates with the defaults.
If Message is empty then I can only assume no information is being returned from the HRESULT.