Jump to content
Professor_Bernd

Use AutoItX as COM ROT object, without regsvr32 registration

Recommended Posts

Since my COM knowledge is very modest, I may be confusing terms. Please excuse this and try to understand what I mean. ;)

In my PSPad4AutoIt3 project I use AutoItX in PSPad's VBScript. AutoItX was automatically installed with AutoIt3 setup and thus registered in the system via regsvr32. In VBScript I can create a COM object and access its functions. Example:

Set oAutoItX = WScript.CreateObject("AutoItX3.Control")
hPSPadWin = oAutoItX.WinGetHandle("[active]")

Up to this point it works wonderfully. Unfortunately this makes PSPad4AutoIt3 dependent on the regsvr32 registration of AutoItX in the system.

To make PSPad4AutoIt3 independent of this, the task now is to be able to create and use AutoItX COM ROT objects in PSPad's VBScript.

My idea was to create an Au3 script, use ptrex's "HEX Editor COM Control" and LarsJ's "IRunningObjectTable Interface" to register the "AutoItX3.dll" in the ROT and use the AutoItX COM objects in PSPad's VBScript.

In this post LarsJ gave a hint how creating an AutoItX COM object in an Au3 script could work.

My question now is, how can I access this AutoItX COM object in PSPad's VBScript?


For testing, I have uploaded a test version of PSPad4AutoIt3 here. This will be removed when the tests are over.

Prof Bernd. :graduated:

Share this post


Link to post
Share on other sites
Posted (edited)

@Professor_Bernd  

Let's clear out some things first :

1. Using AutoitX as a regFree COM object that was demonstrated in the HEX Editor and Lars iRunningObjectTable Interface, is a unique AUTOIT feature that is not available in VBSCRIPT 😞

So you can forget all of this...

What you are asking is how to work with a REGFREE COM Object in VBSCRIPT to make it portable. 

https://docs.microsoft.com/en-us/windows/win32/sbscs/creating-registration-free-com-objects

This is not an AutoIT question though, but rather how to use COM Object Regfree, where RegSvr32 is not involved

If you look into my signature I posted something many year ago when XP was still alive.

I haven't looked back since to see this technique still works ?

Microsoft has faded out VBScript in favor of .NET so I am not sure if this feature is still available in Windows 10.

I will have a quick look to see what I can find.

See here for the solution : 

https://www.autoitscript.com/forum/topic/204813-use-autoitx-as-com-rot-object-without-regsvr32-registration/?do=findComment&comment=1472602

Edited by ptrex

Share this post


Link to post
Share on other sites

@Professor_Bernd  

I see that this is supported in .NET but I am not sure it still works for VBSCRIPT

And it is a complex process using development tools to create a manifest file.

https://ingeno.io/2016/09/registration-free-com-component-activation/

 

What I can offer as a quick workaround is that you skip the AutoitX COM object and switch over to the cmd option,

Create a VBSCRIPT like this :

 

Dim WshShell
Dim str 
Set WshShell = CreateObject("WScript.Shell") 
str = "C:\TEMP\AutoIt3_x64.exe /AutoIt3ExecuteLine " & chr(34) &"MsgBox(0, 'Hello World', 'Hi')"& chr(34)
msgbox str 
Call WshShell.run (str)

set wshshell = Nothing

 

1. Copy the AutoIt3_x64 to your script folder ex. C:\TEMP\AutoIt3_x64.exe

2. And run the AutoIt cmdline

 

This way you are portable, you can also call functions in a AU3 script using the cmdline if I remember well. 

 


Share this post


Link to post
Share on other sites
Posted (edited)

I think you're making it more troublesome than it really is.

If you copy the first small AutoIt codebox and the first small VBScript codebox at the top of Executing Object Methods through VBScript and more or less replace all instances of "oHexEdit" with "oAutoItX", then I think you have everything you need.

The problem with the oHexEdit object is that the SetData() method returns errors in the AutoIt code. Then we can try to pass the oHexEdit object to VBScript and execute the SetData() method in VBScript code. And fortunately, it works.

Because the AutoIt code and the VBScript code run in two different processes, we need a system global ROT object to pass the oHexEdit object from the AutoIt code to the VBScript code. The ROT object is a simple dictionary object. A key/item pair in this dictionary object is used to pass the oHexEdit object. The key value is just a string to identify the key/item pair. The item value is the object itself.

The problem with the oAutoItX object is that we do not know how to create this object in VBScript code without first registering the object with the regsvr32 program. But we do not want to use regsvr32. In return, we know how to create oAutoItX in AutoIt code without registering the object with regsvr32. Can we not just create oAutoItX in AutoIt code and then pass the object to VBScript code in the same way as we did with oHexEdit. Of course we can. The procedure for oAutoItX is exactly the same as the procedure for oHexEdit.

The technique demonstrated in Executing Object Methods through VBScript is generally applicable and can be used for many different purposes.

That the Dictionary object is the default object in the ROT_RegisterObject() function is not random. The dictionary object is generally applicable and can be used for many different purposes.

Edited by LarsJ

Share this post


Link to post
Share on other sites

@ptrex

I have already tried some ways to call AutoIt in VBScript, e.g. "/AutoIt3ExecuteLine". Likewise, I have tried some COM server ways to use it in VBScript, e.g. Access AutoIt by trancexx, May 14, 2011.

All these possibilities are so slow that they cannot be called in a loop without almost freezing the other execution of e.g. PSPad.

The only one that works fast enough is "IRunningObjectTable Interface" by LarsJ. Although I was able to set up the communication between AutoIt and PSPad's VBScript with LarsJ's help, this doesn't allow to use functions that are not for data exchange, e.g. WinGetHandle(), ControlGetFocus(), ...

If you don't see a way to use AutoIt3.dll in a way that is fast enough, that's fine. It was just an attempt. I thank you for your help. 👍

Share this post


Link to post
Share on other sites

  

@LarsJ

Again, with your tip, I feel like this can work! 👍

I think I understand your planned approach. Actually, it should be quite simple: In AutoIt create a COM object from the AutoIt3.dll, then create a COM object with a dictionary and store the AutoIt3.dll object as a key value in the dictionary. Both objects are registered in the ROT. After that in PSPad's VBScript you only need to take the AutoIt3.dll object from the dictionary.

At least that's how I imagine it. :P

Ok, as I said in the other thread, because I want to finish my current work first, I can't really deal with this new topic until next month. I hope I may ask for help again then. :)

In the meantime, if anyone wants to experiment with PSPad to execute instructions with the registration-free AutoIt3.dll object in PSPad's VBScript, they are welcome to use the test version in the first posting, which I'll leave online until then.

Many thanks to you, LarsJ, for your valuable help! :graduated:

Share this post


Link to post
Share on other sites

I've tested the code here:

#AutoIt3Wrapper_UseX64=Y ; Error if not AutoItX3_x64.dll is registered with regsvr32: The server threw an exception. Code: 80010105
;#AutoIt3Wrapper_UseX64=N ; Error if not AutoItX3.dll is registered with regsvr32: The server threw an exception. Code: 80010105

#include "IRunningObjectTable.au3"

Global $hActiveX

; Load the ActiveX Module
If @AutoItX64 Then
  $hActiveX  = DllOpen(@ScriptDir & "\AutoItX3_x64.dll")
Else
  $hActiveX  = DllOpen(@ScriptDir &  "\AutoItX3.dll")
EndIf
;MsgBox(0,"x64",@AutoItX64)

; Object identifiers
Global Const $sCLSID = "{1A671297-FA74-4422-80FA-6C5D8CE4DE04}"
Global Const $sIID = Default ; Or use keyword Default if you want to use the Default interface ID

; Error Monitoring
Global $oError = ObjEvent("AutoIt.Error", "_ErrFunc")
Func _ErrFunc()
  ConsoleWrite("! COM Error ! Number: 0x" & Hex($oError.number, 8) & " ScriptLine: " & $oError.scriptline & " - " & $oError.windescription & @CRLF)
  Exit
EndFunc    ;==>_ErrFunc

; Create the hActiveX
Local $oAutoIt = ObjCreate($sCLSID, $sIID, $hActiveX)
DllClose($hActiveX)

If $oAutoIt = 0 Then MsgBox(16,"Error", "Could not create the object, Common problem ActiveX not registered.")

; ROT object
ROT_RegisterObject( Default, "DictionaryData" ) ; Default => Object = Dictionary object
$oROTobj = ObjGet( "DictionaryData" ) ; Get the ROT object, the Dictionary object
$oROTobj( "oAutoIt" ) = $oAutoIt ; Key/item pair, Key = "oAutoIt", Item = $oAutoIt

; Run WBScriot code
RunWait( 'wscript.exe "tst02.vbs"' )
;RunWait( @AutoItExe & " /AutoIt3ExecuteScript " & '"tst02Cli.au3"' )
; The error occurs in both VBScript and AutoIt client code

$oAutoIt = ""

with both a VBScript client: (tst02.vbs)

Dim oROTobj, oAutoIt
Set oROTobj = GetObject( "DictionaryData" ) 'Get the ROT object, the Dictionary object

Set oAutoIt = oROTobj( "oAutoIt" ) 'Get oAutoIt object from the key/item pair in the Dictionary object through the key value

'This will create a tooltip
oAutoIt.ToolTip "This is a tooltip", 450, 200
oAutoIt.Sleep 3000 'Sleep to give tooltip time to display

and an AutoIt client: (tst02Cli.au3)

$oROTobj = ObjGet( "DictionaryData" )

$oAutoIt = $oROTobj( "oAutoIt" )

$oAutoIt.ToolTip("This is a tooltip", 450, 200)
$oAutoIt.Sleep(3000)

It seems that the ROT object doesn't work properly unless the relevant AutoItX3 dll is registered with regsvr32.

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

Hello LarsJ.

I have now done a lot of tests with your new code, unfortunately unsuccessfully. It works as long as you work in a Windows where AutoItX is registered via regsvr32. But in a Windows without regsvr32 registered AutoItX the code does not work, because there the CLSID "{1A671297-FA74-4422-80FA-6C5D8CE4DE04}" does not exist in the registry.

I also tried it with the CLSID that trancexx mentioned here. Unfortunately also unsuccessful. :(

I thank you for the last code, with which I could learn a lot! 👍

@LarsJ + @ptrex Thank you so much for the tests and the effort you put into this! :) Maybe a solution will be found later.

Prof Bernd :graduated:

 

Share this post


Link to post
Share on other sites

The goal is to make PSPad4AutoIt3 fully portable. There are users who use AutoIt as a portable version, or even multiple portable versions. Apart from the fact that the user may not want PSPad to register its own AutoItX3.dll, there are complications in any case. E.g. if the PSPad folder is moved, or if the regsvr32.exe needs administrator privileges, etc. For PSPad4AutoIt3 to be fully portable, it should be independent of external preconditions.

Share this post


Link to post
Share on other sites

@Professor_Bernd 

I got something running using the RegFree COM approach.

At least is tested on my Win10 using VBScript and PowerShell

This is how you can test it :

1. UNREGISTER the COM object first using regsvr32 /u AutoItX3_x64.dll

2. Create a MANIFEST file using this content, and save it using this EXACT name :  AutoItX3.sxs.manifest

Quote

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
    type="win32"
    name="AutoItX3.sxs"
    version="1.0.0.0" />

<file name="AutoItX3_x64.dll">

    <comClass
        description="AutoItX3 Class"
        clsid="{1A671297-FA74-4422-80FA-6C5D8CE4DE04}"
        threadingModel="Apartment"
        progid="AutoItX3.Control"
        tlbid="{F8937E53-D444-4E71-9275-35B64210CC3B}" />

</file>

</assembly>

3. Create a Test.vbs using this content :

Quote

Dim o
Set o = CreateObject("Microsoft.Windows.ActCtx")
o.manifest = "C:\Temp\AutoItX3.sxs.manifest"

Dim obj
Set obj = o.CreateObject("AutoItX3.Control")

Msgbox "You are now running AutoItX3.Control Version : " + obj.Version

Set obj = Nothing
Set o = Nothing

4. Copy the 3 files to the C:\Temp folder :

- AutoItX3_x64.dll

- AutoItX3.sxs.manifest

Test.vbs

5. Run this Test.vbs

 

 


Share this post


Link to post
Share on other sites

Wow, that's amazing! 👍

I've read various things about "Registration-Free Activation of COM Components" here (Step 6 and 7) and here, but I haven't figured out what data to put in. For example, where did you get the CLSID and the TLBID? Or how do you get the data for: Set o = CreateObject("Microsoft.Windows.ActCtx") ? :huh2:

I have extended your code a little bit, so that you can use the VBScript file "Test 2.vbs" independent of the path. Attached is the file "2021-01-08 ptrex RegFree COM approach 2.zip", in it is 1 version for Win x32 and 1 version for Win x64. On Win x64 you can drag the "Test 2.vbs" in the x32 folder to the shortcut to wscript.exe x32 (in SysWOW64).

Displaying a ToolTip does NOT work, but starting and closing Notepad does. So we are one step closer to the goal. :)

2021-01-08 ptrex RegFree COM approach 2.zip

Share this post


Link to post
Share on other sites

I mentioned before; already in a previous life I already created this example. 

Which I forgot about 🤥

The CLSID and TLBID you can find in the  manifest file in the ZIP file included. 

Or you can use the TyoeLib Viewer created by the COM guru trancexx

The rest you can find on the internet regarding the COM Free stuff.

Microsoft.Windows.ActCtx object

https://docs.microsoft.com/en-us/windows/win32/sbscs/microsoft-windows-actctx-object

 

 


Share this post


Link to post
Share on other sites

ToolTip is working in PowerShell so probably it is a limitation of VBScript ?

Quote

CLS

$Runspace = [runspacefactory]::CreateRunspace()

$Runspace.ApartmentState = "STA" # Change here !
$Runspace.ThreadOptions = "ReuseThread"

$PowerShell = [powershell]::Create()

$PowerShell.Runspace = $Runspace

$Runspace.Open()

$host.Runspace.ThreadOptions.value__
$Runspace.RunspaceStateInfo

# Start 
$string = { 

$obj = New-Object -COM Microsoft.Windows.ActCTX

$obj.Manifest = "C:\Temp\AutoItX3.sxs.manifest"

$oAutoIt = $obj.CreateObject('AutoItX3.Control')

write-host "You are running AutoIt version :  " $oAutoIt.Version 

If ($oAutoIt.IsAdmin){
    write-host "Your user have Admin rigths"
    write-host ""
   }  

$oAutoIt.Run("notepad.exe", "", $oAutoIt.SW_SHOWNORMAL)

$oAutoIt.ToolTip("This is a tooltip", 450, 200)
$oAutoIt.Sleep(3000)

}

#End

[void]$PowerShell.AddScript($string)

$PowerShell.Invoke() 

$PowerShell.EndInvoke

$Runspace.Close()
$Powershell.Dispose()

 


Share this post


Link to post
Share on other sites
Posted (edited)
parseTTip()
Func parseTTip()
    Local $iWait = 1000
    Local $text = "sample tooltip"
    Local $x = Default
    Local $y = Default
    Local $title = ""
    Local $icon = 0
    For $n = 1 To $CmdLine[0]
        Switch $n
            Case 1
                $iWait = Int($CmdLine[$n])
            Case 2
                $text = $CmdLine[$n]
            Case 3
                $x = Int($CmdLine[$n])
            Case 4
                $y = Int($CmdLine[$n])
            Case 5
                $icon = Int($CmdLine[$n])
        EndSwitch
    Next
    TTip($iWait, $text, $x, $y, $title, $icon)
EndFunc

Func TTip($iWait, $text = "sample tooltip", $x = Default, $y = Default, $title = "", $icon = 0)
    ToolTip($text, $x, $y, $title, $icon)
    Sleep(Int($iWait))
EndFunc

you can call something like this ( compiled ) from a VBS and solve the tooltip limitation. Not elegant but, if it does the job. :)

object.Run(strCommand, [intWindowStyle], [bWaitOnReturn])

Edited by argumentum

Share this post


Link to post
Share on other sites
1 hour ago, ptrex said:

ToolTip is working in PowerShell so probably it is a limitation of VBScript ?

Thanks to @Danyfirex and @jpm we know why....
https://www.autoitscript.com/trac/autoit/ticket/3164

 


Signature beginning:   Wondering who uses AutoIt and what it can be used for ?
* GHAPI UDF - modest beginning - communication with GitHub REST API Forum Rules *
Include Dependency Tree (Tool for analyzing script relations)
ADO.au3 UDF     POP3.au3 UDF     XML.au3 UDF    How to use IE.au3  UDF with  AutoIt v3.3.14.x  for other useful stuff click the following button

Spoiler

Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind. 

My contribution (my own projects): * Debenu Quick PDF Library - UDF * Debenu PDF Viewer SDK - UDF * Acrobat Reader - ActiveX Viewer * UDF for PDFCreator v1.x.x * XZip - UDF * AppCompatFlags UDF * CrowdinAPI UDF * _WinMergeCompare2Files() * _JavaExceptionAdd() * _IsBeta() * Writing DPI Awareness App - workaround * _AutoIt_RequiredVersion() * Chilkatsoft.au3 UDF * TeamViewer.au3 UDF * JavaManagement UDF * VIES over SOAP * WinSCP UDF * GHAPI UDF - modest begining - comunication with GitHub REST APIErrorLog.au3 UDF - A logging Library *

My contribution to others projects or UDF based on  others projects: * _sql.au3 UDF  * POP3.au3 UDF *  RTF Printer - UDF * XML.au3 UDF * ADO.au3 UDF SMTP Mailer UDF * Dual Monitor resolution detection * * 2GUI on Dual Monitor System * _SciLexer.au3 UDF * SciTE - Lexer for console pane

Useful links: * Forum Rules * Forum etiquette *  Forum Information and FAQs * How to post code on the forum * AutoIt Online Documentation * AutoIt Online Beta Documentation * SciTE4AutoIt3 getting started * Convert text blocks to AutoIt code * Games made in Autoit * Programming related sites * Polish AutoIt Tutorial * DllCall Code Generator * 

Wiki: Expand your knowledge - AutoIt Wiki * Collection of User Defined Functions * How to use HelpFile * Good coding practices in AutoIt * 

OpenOffice/LibreOffice/XLS Related: WriterDemo.au3 * XLS/MDB from scratch with ADOX

IE Related:  * How to use IE.au3  UDF with  AutoIt v3.3.14.x * Why isn't Autoit able to click a Javascript Dialog? * Clicking javascript button with no ID * IE document >> save as MHT file * IETab Switcher (by LarsJ ) * HTML Entities * _IEquerySelectorAll() (by uncommon) * IE in TaskSchedulerIE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) *

PDF Related:How to get reference to PDF object embeded in IE *

I encourage you to read: * Global Vars * Best Coding Practices * Please explain code used in Help file for several File functions * OOP-like approach in AutoIt * UDF-Spec Questions *  EXAMPLE: How To Catch ConsoleWrite() output to a file or to CMD *

I also encourage you to check awesome @trancexx code:  * Create COM objects from modules without any demand on user to register anything. * Another COM object registering stuffOnHungApp handlerAvoid "AutoIt Error" message box in unknown errors  * HTML editor

"Homo sum; humani nil a me alienum puto" - Publius Terentius Afer
"Program are meant to be read by humans and only incidentally for computers and execute" - Donald Knuth, "The Art of Computer Programming"
:naughty:  :ranting:, be  :) and       \\//_.

Anticipating Errors :  "Any program that accepts data from a user must include code to validate that data before sending it to the data store. You cannot rely on the data store, ...., or even your programming language to notify you of problems. You must check every byte entered by your users, making sure that data is the correct type for its field and that required fields are not empty."

Signature last update: 2021-01-03

Share this post


Link to post
Share on other sites

Challenge asked for was :

Have VBScript call Windows API's and make it Portable.

This is how you can test it :

1. Put the dynwrap.dll in the folder c:\TEMP

2. Put this content in a file called dynwrap.sxs.manifest file in the same folder as the DynWrap.dll

Quote

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
    type="win32"
    name="dynwrap.sxs"
    version="1.0.0.0" />

<file name="dynwrap.dll">

    <comClass
        description="dynwrap.dll"
        clsid="{202774D1-D479-11d1-ACD1-00A024BBB05E}" 
    threadingModel="Apartment"
        progid="DynamicWrapper"/>

</file>

</assembly>

3. Save this VBScript in the same folder as TEST.VBS

Quote

Option Explicit

Dim fso, objShell, ScriptPath, ScriptDir

ScriptPath = WScript.ScriptFullName
Set fso = CreateObject("Scripting.FileSystemObject")
ScriptDir = fso.GetParentFolderName(ScriptPath)

Set objShell = CreateObject("Wscript.Shell")
' Msgbox objShell.CurrentDirectory      ' show WorkingDirectory
objShell.CurrentDirectory = ScriptDir ' set WorkingDirectory

Dim oActCtx
Set oActCtx = CreateObject("Microsoft.Windows.ActCtx")
oActCtx.manifest = "dynwrap.sxs.manifest"

Dim obj
Set obj = oActCtx.CreateObject("DynamicWrapper")

Msgbox "You are calling RegFree Windows API's from VBScript !" 

' Call MessageBoxA(), first register the API function
obj.register "USER32.DLL", "MessageBoxA", "I=HsSu", _
                 "f=s", "R=l"

' call the MessageBoxA 
obj.MessageBoxA Null, "MessageBox (ANSI)", "VBS Next Level From DynaWrap Object - Check your Clipboard !!", 3

Set obj = Nothing
Set oActCtx = Nothing


' clipboard set data 
Dim oActCtx1
Set oActCtx1 = CreateObject("Microsoft.Windows.ActCtx")
oActCtx1.manifest = "dynwrap.sxs.manifest"

Dim data, objc, b, c

Set objc = oActCtx1.CreateObject("DynamicWrapper")

data = "VBScript has called the Win API Clipboard"

objc.register "kernel32.dll", "GlobalAlloc", "i=uu", "f=s", "r=l"
objc.register "kernel32.dll", "GlobalLock", "i=l", "f=s", "r=l"
objc.register "kernel32.dll", "lstrcpy", "i=hs", "f=s", "r=h"
objc.register "user32.dll", "OpenClipboard", "i=h", "f=s", "r=l"
objc.register "user32.dll", "EmptyClipboard", "f=s", "r=l"
objc.register "user32.dll", "SetClipboardData", "i=uh", "f=s", "r=l"
objc.register "user32.dll", "CloseClipboard", "f=s", "r=l"

b = objc.lstrcpy(objc.GlobalLock(objc.GlobalAlloc(0, cint(len(data)+1))), cstr(data))

c = objc.OpenClipboard(0)
c = objc.EmptyClipboard()
c = objc.SetClipboardData(1, b)

c = objc.CloseClipboard()

Set objc = nothing

4. Run it script by dropping the VBScript on the wscript.exe x32 (in SysWOW64) shortcut

 

TESTED and working on :

Windows 10 / Server 2008 / Server 2019

Enjoy !

 

PS : Correction

- File path in Manifest was wrong.

- Corrected typo's again 😞

- Added test results different OS's

 

dynwrap.zip

Edited by ptrex

Share this post


Link to post
Share on other sites
2 hours ago, ptrex said:

Set obj = oActCtx.CreateObject("DynamicWrapper")

Line:   18
Char:   1
Error:  ActiveX component can't create object
Code:   800A01AD
Source:     Microsoft VBScript runtime error

just in case: I did correct the path in the manifest and did run the x86 version

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...