Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

.NET Framework Interop


  • Please log in to reply
155 replies to this topic
ProgrammerPaul
  • Members
  • 75 posts
  • Last active: Oct 05 2017 01:14 PM
  • Joined: 28 May 2009
Thanks for the quick response Lexikos!
I was able to get this to work correctly on my Windows XP machine, but I haven't had much luck on Vista, Windows 2008 or Windows 2008 R2. I did find that the A_WinDir variable (in CLR.ahk) is returning C:\Users\Paul\Windows instead of C:\Windows (on Windows 2008 and up), but even when I hard code that it still fails. When I use the following code, I get this error:

---------------------------
COM Error Notification
---------------------------
Function Name: "CreateInstance"
ERROR: No COM Dispatch Object!
()

Will Continue?
---------------------------
Yes No
---------------------------

I also made sure I had the latest Autohotkey_L and tried different combinations of the install options. I don't know if it matters, but I think the only machine that it worked correctly on was a 32bit machine.

			vb =
			(
			    Imports System.Windows.Forms
			    Class Foo
				Public Sub Test()
				microsoft.visualbasic.msgbox("this is nuts!")
				    MessageBox.Show("Hello, world, from VB!")
				End Sub
			    End Class
			)

			CLR_Start()

			asm := CLR_CompileVB(vb, "System.dll | System.Windows.Forms.dll")
			obj := CLR_CreateObject(asm, "Foo")
			COM_Invoke(obj, "Test")
			COM_Release(obj), COM_Release(asm)

Thanks so much for your help! I can't wait to dive into this. VB.net and Autohotkey are my two favorite languages. My chocolate and peanut butter, if you will. :)

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
[*:36jpf87r]Does the following show 1 or 0?
MsgBox % IsObject(CLR_LoadLibrary("System"))
[*:36jpf87r]What if you pass the version number explicitly to CLR_Start?
[*:36jpf87r]Can you confirm that <WinDir>\Microsoft.NET\Framework\v<version number>\mscorlib.dll exists?
[*:36jpf87r]Your example works on my Windows 7 64-bit system (but 32-bit AutoHotkey since CLR.ahk doesn't support 64-bit yet). Does A_WinDir return that value on Vista, or only on Server 2008? Is it a Terminal Server?

Terminal Services: If the application is running in a Terminal Services environment, each user has a private Windows directory. There is also a shared Windows directory for the system. If the application is Terminal-Services-aware (has the IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE flag set in the image header), this function returns the path of the system Windows directory, just as the GetSystemWindowsDirectory function does. Otherwise, it retrieves the path of the private Windows directory for the user.
Source: GetWindowsDirectory Function

AutoHotkey uses GetWindowsDirectory. (Related post.)

ProgrammerPaul
  • Members
  • 75 posts
  • Last active: Oct 05 2017 01:14 PM
  • Joined: 28 May 2009
I found out that I was running into a security issue with the dotnet framework. I was trying to load the assembly over the network instead of from a local drive which put it into a more restrictive zone. Once I got the dll on the local drive and made sure I was using the 32 bit version things started working correctly.
I think the A_WinDir issue is related to the machines being configured as Terminal Servers or being logged in remotely.
I reviewed the post you linked to. It looks like having the A_WinDir directory point to the local user profile folder makes sense for configuration files, but it's not really intended for something like the Microsoft/Framework directories as everything would have to be copied down. Or redirected under the covers. Neither of which seems to happen.
I did find what appears to be a standard environmental variable that returns the "real" windows directory even on a Windows server:
EnvGet outVar, SystemRoot

That might be another option.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Thanks; I've changed it to use SystemRoot.

I think the A_WinDir issue is related to the machines being configured as Terminal Servers or being logged in remotely.

Right. The quote in my previous post explains.

perlguy
  • Members
  • 2 posts
  • Last active: May 29 2011 09:27 PM
  • Joined: 04 Mar 2011
Hi all... Sean, Lexikos - can't thank you enough for all you've added to AHK... it makes life under Windows almost enjoyable. :)

No questions (ok... I do have one - at the very end) - I just thought I'd post the results of my beat-head-on-wall marathon the past day or so. I'm a unix admin... not new to programming.. but c/perl/shell/ruby/etc, especially coming from the unix world does nothing to prepare you for the convolutions you go through to make things happen on windows. To be fair... most of my problems were because I thought I had checked, a few times, to be sure I had the COM_L version in lib\, but somehow I had the one from COM... once that was corrected, things went really quickly.

Any chance COM and CLR (regular and _L versions, 32bit vs 64bit) could get a comment at the top, mentioning which variant it was? Would sure have made it easier to notice which version it was, without having to re-download from the forum, and compare file sizes.

Anyway - I finally got Lexikos' event handler example working with the latest AHK_L, COM_L and CLR_L. Which is amazing, since until 36 hours ago, I had never even looked as C#... or built anything with CLR. Now that I have the example working, hopefully I can implement a network address change daemon, that I can use to trigger other ahk scripts when adapters change state or address. Automate updating proxy settings, primarily, but I have other things too.

Biggest changes to get it working were converting everything to "." notation - which makes it much more readable too (double win). Oh, I changed the ahk handler function name (prefixed with "Ahk" now) so it would be less confusing which was being referred to in the various locations.

Revised EventHandler:

#Persistent

AhkEventHandler(vt, junk1, sender, junk2, eventArgs)
{
    MsgBox, 0, Event Raised, % "sender: " COM_Invoke(sender,"ToString")
        . "`neventArgs: " COM_Invoke(eventArgs,"ToString")
	 ExitApp
}

c# =
(
    using System;
    using System.Runtime.InteropServices;
    
    class ObjectWithEvent {
        public void RaiseEvent() {
            if (OnEvent != null)
                OnEvent(this, EventArgs.Empty);
        }
        public event EventHandler OnEvent;
        
        public Delegate Delegate4FuncPtr(uint ptr, Type t) {
            return Marshal.GetDelegateForFunctionPointer((IntPtr)ptr, t);
        }
    }
)

asmCor := CLR_LoadLibrary("mscorlib")
; Get typeof(System.EventHandler)
tEH := asmCor.GetType_2("System.EventHandler")
; Create Event Handling object
obj := CLR_CompileC#(c#, "System.dll").CreateInstance("ObjectWithEvent")
; Create a .NET Delegate for the AhkEventHandler() callback.
pEH := obj.Delegate4FuncPtr( RegisterCallback("AhkEventHandler"), tEH)

; Register the event handler. (Events export add_event() and remove_event()).
obj.add_OnEvent(COM_Parameter(13,pEH))
; Call the C# method which raises the event.
obj.RaiseEvent()

Return

What I hope to springboard to next: adapting this to be the event receiver for network changes on my LAN and WiFi interfaces... a limited form of hald or d-bus for networking. If anyone knows of a better way I'm all ears. Anything except polling I mean - that I could manage (lots of options there - ifconfig, netsh, registry, etc), but subscribing to the event that's available has to be more efficient than anything using ifconfig or netsh (or even polling the registry keys for changes).

When I have something working in reasonable presentable shape - I'll be sure to post it.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Any chance COM and CLR (regular and _L versions, 32bit vs 64bit) could get a comment at the top, mentioning which variant it was?

I've added headers to CLR and CLR_L, but you'll have to ask Sean about COM. Btw, there are is no 64-bit version of either script...

perlguy
  • Members
  • 2 posts
  • Last active: May 29 2011 09:27 PM
  • Joined: 04 Mar 2011
Ah. That's right... guess I was thinking of AHK itself...

Thanks!

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
I want to use a DLL written in CSharp.

So here's my code:
1:#Include CLR.ahk
2:#Include COM.ahk
3:
4:CLR_Start()
5:
6:asm := CLR_LoadLibrary("USBHIDDRIVER.dll") ; the dll has been registered with regasm
7:
8:obj := CLR_CreateObject(asm, "USBHIDDRIVER.USBInterface","vid_06f8","pid_d100")
9:
10:COM_Invoke_(obj, "Connect")
11:
12:COM_Release(obj)
13:COM_Release(asm)


but I get

"
Function Name: Connect()
ERROR: The COM Object may not be a valid Dispatch Object!
First ensure that COM Library has been initialized though COM_Init()()
"....

I tried calling COM_Init after CLS_Start but got same message ...

Help me please :(

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Learn to debug your code. Obviously obj is not a valid object, so CLR_LoadLibrary and/or CLR_CreateObject failed. You can easily detect it by checking the value of asm or obj (e.g. using a MsgBox or ListVars/Pause). You can also check the COM_HR variable after each call; it may contain an error code.

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
wrt to Debug:
Lexikos, i am not fully aware of AHK potential yet.

I discovered it yesterday and saw how much powerfull it is. I manage to use AHKHID immediately and was pretending to be as fast on extending its functionalities to suit my need ...

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
ok it's the latter that don't do the trick:

asm := CLR_LoadLibrary("c:\USBHIDDRIVER.dll")
MsgBox % asm

shows "59375408"

whereas

obj := CLR_CreateObject(asm, "USBHIDDRIVER.USBInterace","Str","vid_06f8","Str","pid_d100")
msgBox % obj

shows "0"

I did several attemps but no success... any suggestion is welcome to understand why the constructor is not called

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
OK I am almost there:

CLR_Start()


asm := CLR_LoadLibrary("c:\USBHIDDRIVER.dll")
obj := CLR_CreateObject(asm, "USBHIDDRIVER.USBInterface","Str","Vid_06f8","Str","pid_d100")

obj is not null
The problem is later when I try to run methods on that object ... nothing works
got -1 returned by each function ... from connect to write :/

??????????????????????????????????????????????????????????
Furthermore now with msinfo I've seen that I have to peripherals with same vendor and pid one is the USBHID the other one is smthing consumer control peripheral HID compliant ...

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
According to this blog, connect and write return boolean values; true on success, false on failure. -1 in COM is the equivalent of true, so your function calls are "succeeding". Perhaps you are connecting to the wrong device, or sending data it doesn't understand. If you post more of your code, I may be able to help, but not beyond basic usage of CLR.ahk. I am a bit curious about how you're passing the byte array, since you seem to be using AutoHotkey Basic which doesn't natively support COM arrays.

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
-1 means TRUE in COM ??!?! I hate Microsot!!!
I spent all afternoom thinking it was not working but in fact it does ....grrrrr


Lexicos thnks a lot
Wrt to passing byte array I was working on that :)
I suppose I will have to start all over again an use your version


Thanks again

BrunoC
  • Members
  • 24 posts
  • Last active: Mar 16 2011 08:20 PM
  • Joined: 09 Mar 2011
OK I managed to move to the Lexikos version

....
now I just have to find a way to build a byte array :)