Accessing data from DLL - c#

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

Related

C# vs PowerShell. How to get detailed exception info?

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

Runtime casting of COM objects in C#

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.

Running python functions using IronPython in C#

Im trying to import use a python script in C# by using IronPython but an error keeps coming up which I don't understand, seems like it had problems importing the module. The python file runs fine by itself and i tested a simple script that prints "hello" and it worked so I might just be importing the module wrong somehow.
An unhandled exception of type 'System.MissingMemberException' occurred in Microsoft.Dynamic.dll
Additional information: 'module' object has no attribute 'setup'
Error Image
This is the code im trying to run on my C# program
var engine = Python.CreateEngine();
ICollection<string> paths = engine.GetSearchPaths();
string modulePath = #"D:\Python\Lib";
paths.Add(modulePath);
string modulePath2 = #"D:\Python\Lib\site-packages";
paths.Add(modulePath2);
engine.SetSearchPaths(paths);
dynamic py = engine.ExecuteFile(#"broadlink.py");
This is the code in my python
import broadlink
broadlink.setup('*****', '*****', 3)
devices = broadlink.discover(timeout=5)

Sikuli Integrator C# errors

I try to use Sikuli Integrator for C#.
I create new project in Visual Studio 2015, and I Install SikuliIntegrator.
After the installation JSikuliModule.jar, it will be part of my solution, together with some additional files. After that Properties to set “Copy to Output Directory” property to “Copy always” of JSikuliModule.jar
and then I try my code :
class Program
{
static void Main(string[] args)
{
String pattern = #"C:\\Users\\amin-\\Documents\\Visual Studio 2015\\Projects\\SikuliTest\\SikuliTest\\img\\logo.png";
SikuliAction.Click(pattern);
//if (SikuliAction.Exists(pattern).IsEmpty)
//{
// Console.WriteLine("Nope! It's gone...");
//}
//else
//{
// Console.WriteLine("Yep! It's there...");
//}
}
}
If I run the code, this is the errors shows :
An unhandled exception of type 'System.UnauthorizedAccessException' occurred in mscorlib.dll Additional information: Access to the path 'C:\SikuliOutputLog.txt' is denied.
If I run the code as an administrator, this is the errors shows :
An unhandled exception of type 'System.Exception' occurred in SikuliModule.dl Additional information: ###FAILURE
Manually create a text file 'C:\SikuliOutputLog.txt' then run the code.
It works for me.
In Windows10 besides manually adding C:\SikuliOutputLog.txt you need also to make sure current user have the 'Write' control to this file.

Methods in reflected DLLs unable to be called. How can I get a better error message?

I'm trying to write a PowerShell script that will call a series of static methods in a static class (MyClass) contained within certain DLL (MyNamespace.MyLibrary.dll) through reflection. However, even calling the simplest of methods (MyNamespace.MyLibrary.MyClass.CallMe()) inside that library fails with the following error message:
Exception calling "CallMe" with "0" argument(s): "The type initializer for 'MyNamespace.MyLibrary.MyClass' threw an exception."
At C:\temp\powershellTest.ps1:41 char:1
+ $output = [MyNamespace.MyLibrary.MyClass...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TypeInitializationException
The first odd thing is that I'm getting a type initialization (constructor?) error when trying to call a static method in a static class.
The PowerShell code making the call:
[reflection.assembly]::LoadFile($dllLocation + 'MyNamespace.MyLibrary.dll')
$output = [MyNamespace.MyLibrary.MyClass]::CallMe()
Write-Host $output
The relevant C# code:
namespace MyNamespace.MyLibrary
{
public static class MyClass
{
public static string CallMe() // the CallMe() method was added just to try to debug this
{
return "I was called";
}
}
}
Now, this particular library is much larger and has many dependencies, all used within other methods in MyClass. I made another DLL that is literally as simple as can be (no external dependencies) to test my powershell reflection, and it succeeds in calling a static class' method (also static, obviously). This tells me that my powershell is correct, so I looked up why I might be getting this issue. This comment says that it may not be automatically loading all of MyNamespace.MyLibrary's references.
I tried two things to remedy that:
I copied all non-GACed DLLs referenced by MyLibrary into the same folder so they'd be side-by-side with MyLibrary.dll
When that didn't work, I also added explicit [reflection.assembly]::LoadFile(path\otherAssembly.dll) lines after the one for MyNamespace.MyLibrary.dll to make sure powershell could load them. This also didn't work.
Here's my main question: How can I get a more specific error message about which dependency isn't being found and possibly where it's looking? I was shocked when Attempted Fix #1 wasn't enough, and I'm not sure what else I can do.
I hope that made sense; feel free to ask any necessary clarifying questions. Thanks!
According to this answer Run script from location that your dlls are copied and try this code:
$currentScriptDirectory = Get-Location
[System.IO.Directory]::SetCurrentDirectory($currentScriptDirectory.Path)
This will give you exception details:
try
{
[reflection.assembly]::LoadFile($dllLocation + 'MyNamespace.MyLibrary.dll')
$output = [MyNamespace.MyLibrary.MyClass]::CallMe()
Write-Host $output
}
catch [Exception]
{
echo $_.Exception.GetType().FullName, $_.Exception.Message
}

Categories