Jump to content

Using .NET libary with AutoIt, possible?


Recommended Posts

 

 

 

Link to comment
Share on other sites

Good to know your still trying to dive into the deep water. 

I am still exploring more the Powershell capabilities. Because it safes all the hassle of the C# wrapper stuff. 

And native .Net classes are available too. But I must admit that it is not that straightforward too. 

For example to get access to Office365 using PS, I still need. Net class libr. to passed the authentication process... 

Still fighting to get that to work. 

Link to comment
Share on other sites

HI All,

Was trying to make some more examples like this OLEDB connection to an Access DB...

But can't get the ConnectionString set ?

Tried many different BindingFlags combinations, but no success... ?

Func Example1()
    ; Call CLR Assembmbly
    Local $oAssembly = _CLR_LoadLibrary("System.Data")
    ConsoleWrite("$oAssembly: " & IsObj($oAssembly) & @CRLF)

    ; Create Object OleDb.OleDbConnection
    Local $pAssemblyType = 0
    $oAssembly.GetType_2("System.Data.OleDb.OleDbConnection", $pAssemblyType)
    ConsoleWrite("$pAssemblyType = " & Ptr($pAssemblyType) & @CRLF)

    Local $oAssemblyType = ObjCreateInterface($pAssemblyType, $sIID_IType, $sTag_IType)
    ConsoleWrite("IsObj( $oAssemblyType ) = " & IsObj($oAssemblyType) & @CRLF)

    ; Connection Object
    Local $Conn = 0
    Local $strConn[] = ["Provider=Microsoft.ACE.OLEDB.12.0;data source=C:\Database1.accdb"]

    ConsoleWrite("$oConn : " & $strConn[0] & @CRLF)

    $oAssemblyType.InvokeMember_3("ConnectionString", $BindingFlags_SetProperty, 0, 0, CreateSafeArray($strConn), $Conn) 
    ConsoleWrite("Connection : " & IsObj($Conn) & $Conn & @CRLF)

EndFunc

Works perfectly if I run this using the Powershell .NET wrapper ...

Here is a C++ variation https://msdn.microsoft.com/en-us/library/aa325886(v=vs.71).aspx

in the meantime I will try to move to a different Example ...

Link to comment
Share on other sites

Forgot to tell you need to add this to all the examples

#AutoIt3Wrapper_UseX64=n

Because if you are using a 32 Bit Office installation you need to use the 32 Bit .NET Assembly too !!

Tried this approach... but how to add the connection string ?

#AutoIt3Wrapper_UseX64=n

#include "CLR.Au3"

Example()

Func Example()
  Local $oAppDomain = _CLR_GetDefaultDomain()

  ; Create an instance using a parameterized constructor
  Local $pHandle
  $oAppDomain.CreateInstance( "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "System.Data.OleDb.OleDbConnection",  $pHandle )
  ConsoleWrite( @CRLF & "$pHandle = " & $pHandle & @CRLF )

  Local $oHandle = ObjCreateInterface( $pHandle, $sIID_IObjectHandle, $sTag_IObjectHandle )
  ConsoleWrite( @CRLF & "IsObj( $oHandle ) = " & IsObj( $oHandle ) & @CRLF )

  ; Unwrap the ArrayList instance inside the ObjectHandle
  Local $oArrayList
  $oHandle.Unwrap($oArrayList)
  ConsoleWrite( @CRLF & "IsObj( $oArrayList ) = " & IsObj( $oArrayList ) & @CRLF )

EndFunc

Also this works but how to add the connection string ?

Example1() ;

Func Example1()
    local $oActivator=getActivator()

    Local $aText[] = ["C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll", "System.Data.OleDb.OleDbConnection"] ; <<<<<<<  Set correct assembly path

    Local $pObject = 0
    $oActivator.InvokeMember_3("CreateComInstanceFrom", 0x158, 0, 0, CreateSafeArray($aText), $pObject)
    ConsoleWrite("IsObject: " & IsObj($pObject) & @TAB & "$pObject: " & ObjName($pObject) & @CRLF)

    Local $oObject = $pObject.Unwrap()
    ConsoleWrite("!$pObject.Unwrap : " & IsObj($oObject) & @CRLF)

EndFunc

Func GetActivator()
    Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    Local $ptActivator = 0
    $oAssembly.GetType_2("System.Activator", $ptActivator)
    Local $oActivator = ObjCreateInterface($ptActivator, $sIID_IType, $sTag_IType)

;~  ConsoleWrite("$oAssembly: " & IsObj($oAssembly) & @CRLF)
;~  ConsoleWrite("$pAssemblyType = " & Ptr($ptActivator) & @CRLF)
;~  ConsoleWrite("IsObj( $oAssemblyType ) = " & IsObj($oActivator) & @TAB & @CRLF)

    Return $oActivator
Endfunc

Any tips are welcome ...

Link to comment
Share on other sites

Found an interesting post in the internet... I seems that ever in the beginning of .NET there existed an BindingFlag that called (BindingFlags.LookupAll)

https://social.msdn.microsoft.com/Forums/vstudio/en-US/12f07316-d077-4db4-8ff0-456c69c5766e/c-reflection-problems?forum=csharpgeneral

This has become obsolete and are is now a combination of, : BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static

So I will add this to the CLR UDF for convenience reasons :

Global Const $BindingFlags_LookupAll = 0x0042

 

Link to comment
Share on other sites

Hello guys nice to see that you are still digging inside this nice stuff. I'll try to keep reading as soon I get free time because You had shared a bunch of information (so I need so much time to read/understand many unkown English terminologies).

 

@ptrex I think to be able to get/set ConnectionString You need to use PropertyInfo Class , or for set probably using  the constructor's parameter.

Saludos

Link to comment
Share on other sites

Hi DanyFirex,

Thanks for the hint ! Will look at this to see how far I can get it going .

Would very well like to buy you a cup of coffee :) but you are a bit too far out of reach (Venezuela, correct ?)

The closest I can get is Mexico :D

Link to comment
Share on other sites

Link to comment
Share on other sites

Some more good reading form the C# For Anna University B.E. Students : https://csharpdotnet.wordpress.com/2008/10/25/reflection/

Starting with Reflections, Late Binding, over AppDomain, Multithreading and more in a comprehensive way.

Including C# examples.

The content has some millage ... but the concepts described are still very much valid...

Link to comment
Share on other sites

  • 2 weeks later...

Very nice summary in the PDF in the examples section

  • I have been reading 2 books  where we basically have covered the usefull things in this thread.
    The books gave me more theoretical background nicely collected together compared to all stuff scattered around on the internet
    www.johnchukwuma.com/training/clr_via_c_4th_edition.pdf
    https://www.amazon.com/Customizing-Microsoft®-Framework-Developer-Reference/dp/0735619883
  • We only have some things to make examples on or clear out the details 
    • dynamic / dot notation
    • powershell with stdout of AutoIt / Scite 
    • Clean up / rewrite parts with dot notation (when we have that working) and use activator as the base for createinstancexxx method
    • Fix the issue on valuetypes like point x,y
    • ...
  • Things in the books that I feel are not needed in AutoIt to have examples on
    • Managed part requests memory allocation from AutoIt as host
    • Multiple appdomains (I assume in AutoIt it does not add value)
Link to comment
Share on other sites

@Junkew, Thanks .... I hope it covered the basics in the PDF in a very short overview... 

But there are still some nice undiscovered functionality in the CLR.au3 which has not been touched.

See for example the list of the Type Interface... there are still a lot of useful functionality in there which should hit the surface ...

Global Const $sIID_IType = "{BCA8B44D-AAD6-3A86-8AB7-03349F4F2DA2}"
Global Const $sTag_IType = _
    $sTag_IDispatch & _
    "get_ToString hresult(bstr*);" & _
    "Equals hresult(variant;short*);" & _
    "GetHashCode hresult(int*);" & _
    "GetType hresult(ptr);" & _
    "get_MemberType hresult(ptr);" & _
    "get_name hresult(bstr*);" & _
    "get_DeclaringType hresult(ptr);" & _
    "get_ReflectedType hresult(ptr);" & _
    "GetCustomAttributes hresult(ptr;short;ptr);" & _
    "GetCustomAttributes_2 hresult(short;ptr);" & _
    "IsDefined hresult(ptr;short;short*);" & _
    "get_Guid hresult(ptr);" & _
    "get_Module hresult(ptr);" & _
    "get_Assembly hresult(ptr*);" & _
    "get_TypeHandle hresult(ptr);" & _
    "get_FullName hresult(bstr*);" & _
    "get_Namespace hresult(bstr*);" & _
    "get_AssemblyQualifiedName hresult(bstr*);" & _
    "GetArrayRank hresult(int*);" & _
    "get_BaseType hresult(ptr);" & _
    "GetConstructors hresult(ptr;ptr);" & _
    "GetInterface hresult(bstr;short;ptr);" & _
    "GetInterfaces hresult(ptr);" & _
    "FindInterfaces hresult(ptr;variant;ptr);" & _
    "GetEvent hresult(bstr;ptr;ptr);" & _
    "GetEvents hresult(ptr);" & _
    "GetEvents_2 hresult(int;ptr);" & _
    "GetNestedTypes hresult(int;ptr);" & _
    "GetNestedType hresult(bstr;ptr;ptr);" & _
    "GetMember hresult(bstr;ptr;ptr;ptr);" & _
    "GetDefaultMembers hresult(ptr);" & _
    "FindMembers hresult(ptr;ptr;ptr;variant;ptr);" & _
    "GetElementType hresult(ptr);" & _
    "IsSubclassOf hresult(ptr;short*);" & _
    "IsInstanceOfType hresult(variant;short*);" & _
    "IsAssignableFrom hresult(ptr;short*);" & _
    "GetInterfaceMap hresult(ptr;ptr);" & _
    "GetMethod hresult(bstr;ptr;ptr;ptr;ptr;ptr);" & _
    "GetMethod_2 hresult(bstr;ptr;ptr);" & _
    "GetMethods hresult(int;ptr);" & _
    "GetField hresult(bstr;ptr;ptr);" & _
    "GetFields hresult(int;ptr);" & _
    "GetProperty hresult(bstr;ptr;ptr);" & _
    "GetProperty_2 hresult(bstr;ptr;ptr;ptr;ptr;ptr;ptr);" & _
    "GetProperties hresult(ptr;ptr);" & _
    "GetMember_2 hresult(bstr;ptr;ptr);" & _
    "GetMembers hresult(int;ptr);" & _
    "InvokeMember hresult(bstr;ptr;ptr;variant;ptr;ptr;ptr;ptr;variant*);" & _
    "get_UnderlyingSystemType hresult(ptr);" & _
    "InvokeMember_2 hresult(bstr;int;ptr;variant;ptr;ptr;variant*);" & _
    "InvokeMember_3 hresult(bstr;int;ptr;variant;ptr;variant*);" & _
    "GetConstructor hresult(ptr;ptr;ptr;ptr;ptr;ptr);" & _
    "GetConstructor_2 hresult(ptr;ptr;ptr;ptr;ptr);" & _
    "GetConstructor_3 hresult(ptr;ptr);" & _
    "GetConstructors_2 hresult(ptr);" & _
    "get_TypeInitializer hresult(ptr);" & _
    "GetMethod_3 hresult(bstr;ptr;ptr;ptr;ptr;ptr;ptr);" & _
    "GetMethod_4 hresult(bstr;ptr;ptr;ptr);" & _
    "GetMethod_5 hresult(bstr;ptr;ptr);" & _
    "GetMethod_6 hresult(bstr;ptr);" & _
    "GetMethods_2 hresult(ptr);" & _
    "GetField_2 hresult(bstr;ptr);" & _
    "GetFields_2 hresult(ptr);" & _
    "GetInterface_2 hresult(bstr;ptr);" & _
    "GetEvent_2 hresult(bstr;ptr);" & _
    "GetProperty_3 hresult(bstr;ptr;ptr;ptr;ptr);" & _
    "GetProperty_4 hresult(bstr;ptr;ptr;ptr);" & _
    "GetProperty_5 hresult(bstr;ptr;ptr);" & _
    "GetProperty_6 hresult(bstr;ptr;ptr);" & _
    "GetProperty_7 hresult(bstr;ptr);" & _
    "GetProperties_2 hresult(ptr);" & _
    "GetNestedTypes_2 hresult(ptr);" & _
    "GetNestedType_2 hresult(bstr;ptr);" & _
    "GetMember_3 hresult(bstr;ptr);" & _
    "GetMembers_2 hresult(ptr);" & _
    "get_Attributes hresult(ptr);" & _
    "get_IsNotPublic hresult(short*);" & _
    "get_IsPublic hresult(short*);" & _
    "get_IsNestedPublic hresult(short*);" & _
    "get_IsNestedPrivate hresult(short*);" & _
    "get_IsNestedFamily hresult(short*);" & _
    "get_IsNestedAssembly hresult(short*);" & _
    "get_IsNestedFamANDAssem hresult(short*);" & _
    "get_IsNestedFamORAssem hresult(short*);" & _
    "get_IsAutoLayout hresult(short*);" & _
    "get_IsLayoutSequential hresult(short*);" & _
    "get_IsExplicitLayout hresult(short*);" & _
    "get_IsClass hresult(short*);" & _
    "get_IsInterface hresult(short*);" & _
    "get_IsValueType hresult(short*);" & _
    "get_IsAbstract hresult(short*);" & _
    "get_IsSealed hresult(short*);" & _
    "get_IsEnum hresult(short*);" & _
    "get_IsSpecialName hresult(short*);" & _
    "get_IsImport hresult(short*);" & _
    "get_IsSerializable hresult(short*);" & _
    "get_IsAnsiClass hresult(short*);" & _
    "get_IsUnicodeClass hresult(short*);" & _
    "get_IsAutoClass hresult(short*);" & _
    "get_IsArray hresult(short*);" & _
    "get_IsByRef hresult(short*);" & _
    "get_IsPointer hresult(short*);" & _
    "get_IsPrimitive hresult(short*);" & _
    "get_IsCOMObject hresult(short*);" & _
    "get_HasElementType hresult(short*);" & _
    "get_IsContextful hresult(short*);" & _
    "get_IsMarshalByRef hresult(short*);" & _
    "Equals_2 hresult(ptr;short*);"

On of them being the "GetMethod" function which is very usefull and I am missing at the moment... ?

Relating to te PowerShell with stdout of AutoIt / Scite. I tried many to almost all possible combinations and no success...

And the main reason is 2 fold (I guess) the CLR creates a seperate process everytime you start it, Therefor there is a disconnection between te initial au3 process that started the CLR process... and there is noway to get this connected back at least without any hocuspocus...

Secondly the output of the PowerShell CLR is of a type PSOBJECT. Which sdtout does not understand onces returned... So a conversion to String should happen before, and this can only be done in C# middleware code unfortunately...

So personally I gave up on this... because I don't see anymore options to get it going.

Relating to the .Notation this would be very nice, but I can't add anything here to help on this subject,

So I am back to getting to run some more examples when I have the time available, But we need more functionality exposed from the CLR Interfaces as mentioned before to get most interesting .Net classes covered.

Anyhow the CLR is one of the most intriguing subjects see since a long time in AU3 :)

It's a shame so little people jump on the wagon for now... 

 

 

 

Edited by ptrex
Link to comment
Share on other sites

  • From R&D / understanding perspective / reflection yes there are many interface methods to try.
    But I ment more from an end user perspective stuff is covered in the thread (when some issues are resolved)
  • clr runtime starts a new process ---> No, its all in the same process of the hosting application
  • For getMethod now indeed in AutoIt you call it to do the invoke in the end
    But if you have the dynamic example working you do it in C# class and in AutoIt you use just the dot syntax
    But for generic user thats hidden away. Probably persons like @trancexx @Danyfirex  @genius257will write for fun a .NET typelib inspector in AutoIt with these reflection methods but once you have the dynamic example working in C# its easier to build the extension in C# as there are dozens of examples to copy/paste.
    What do you want to do once you have getMethodxxx working?
  • Regarding Powershell objects and stdout it just should work. My guess is some security restrictions.
  • dot syntax. post 338/339 to get it working and I have a few paragraphs in the book explaining dynamic.
    Just not enough time to tryout further.

can you elaborate on this one?  "But we need more functionality exposed from the CLR Interfaces as mentioned before to get most interesting .Net classes covered. "

when you have 338/339 working you can just past the string classname and the dynamic class will handle the method, property calls .
Coming week I will retype the source examples from the book and tryout the example thats mentioned there when using DYNAMIC

Edited by junkew
Link to comment
Share on other sites

CLR does not start a new process, that you can see in the Task Manager of course. But it is a process IN a process architecture

  • A helpful way to think about an AppDomain is to view it as the logical equivalent of a process in a Win32 application.

  • AppDomain provide isolation, creating a hard boundary for managed code just like the process boundary under Win32.

  • Similar to processes, AppDomains can be started and stopped independently, and application faults take down only the AppDomain the fault occurs in, not the process hosting the AppDomain.

Therefor everything that happens in the Appdomain is ISOLATED from the unmanaged Host process ... this is making it hard to get interaction in a conventional way.

The GetMethod is for Convenience reasons to retrieve 1 Method rather then looping through all methods in an Assembly. From the GetMethod combined with the correct Bindingflags. We can get access to the Private / Static methods ...

Bottom line is that I am trying to avoid C# as much as possible ofcource.

Otherwise it's better to go back to the ActiveXPosh COM component as middleware and it will save us all the hard work...

Anyhow i am interested to see if you can bring some news on any of these subjects...

 

Link to comment
Share on other sites

  1. Ok for GetMethod I think then you mean to transform this C# example to AutoIt
    https://stackoverflow.com/questions/483215/how-to-do-dynamic-object-creation-and-method-invocation-in-net-3-5
  2. A bonus if wrapped in dot syntax and as you prefer full AutoIt probably inherit that
    from OOPE.AU3
    https://www.autoitscript.com/forum/topic/178542-oop-extender-v03-stable-real-object-oriented-programming-with-autoit/
    or from AIO pure AutoIt
    https://www.autoitscript.com/forum/topic/185720-autoitobject-pure-autoit/#comment-1362480
  3. dot syntax either thru
    a. IReflect interface  in C# (works from V1.1) (And is used by HP UFT DotNetFactory solution)
    b. but probably easier with dynamicobject (I have partly working example) in C# (works from V4.0)
    c. thru COM (echo example post #339) in C# which looks more complex (but thats probably as COM hides less compared to CLR)

     
  • ActiveX Posh has the disbenefit of registering in registry (with admin rights).
    This whole thread on CLR makes that all registry / regasm independent.
Link to comment
Share on other sites

  • 1 month later...

Played a little with the powershell stuff but come to conclusion

  • such simple thing as hosting powershell in C# and writing to stdout
using System;
using System.Management.Automation;

class Program
{
    static void Main(string[] args)
    {
   //     PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(AppContext.BaseDirectory);

        using (var ps = PowerShell.Create())
        {
            ps.AddScript("Get-Process | Out-String");
            var result = ps.Invoke()[0];
            Console.WriteLine(result.ToString());
        }
    }
}
  • Is terrible hard in AutoIt  (So some people with more AutoIt knowledge hopefully can jump in)

Below more stuff I tried (main issue is getting the PSObjectCollection / PSObject and then call the invoke method stuff)

1. we have to marshal the returned object somehow.

So made a small getMarshal function but I am in doubt if I have the right interface stuff. No clue how to proof that

I assume I should be able to do an invokemember call like sizeof but not working probably as my last $pData is incorrect way of passing it

#include ".\Includes\CLR.au3"
local $oMarshal = getMarshal()
ConsoleWrite("IsObj( $oMarshal ) = " & IsObj($oMarshal) & @TAB & @CRLF)

local $pData
$oMarshal.InvokeMember_3("SizeOf", 0x158, 0, 0, $oMarshal, $pData)
ConsoleWrite("IsObj( $oMarshal data) = " & $pData & @TAB & @CRLF)

func getMarshal()
    Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    Local $ptMarshal = 0
    $oAssembly.GetType_2("System.Runtime.InteropServices.Marshal", $ptMarshal)
    Local $oMarshal = ObjCreateInterface($ptMarshal, $sIID_IType, $sTag_IType)

;~  ConsoleWrite("$oAssembly: " & IsObj($oAssembly) & @CRLF)
;~  ConsoleWrite("$pAssemblyType = " & Ptr($ptMarshal) & @CRLF)
;~  ConsoleWrite("IsObj( $oMarshal ) = " & IsObj($oMarshal) & @TAB & @CRLF)

    return $oMarshal
endfunc

If above works I think that you can transform the returned .NET object to COM with the methods from the marshal class

System_CAPS_pubmethodSystem_CAPS_static GetIDispatchForObject(Object)

Returns an IDispatch interface from a managed object.

System_CAPS_pubmethodSystem_CAPS_static GetIDispatchForObjectInContext(Object)

Returns an IDispatch interface pointer from a managed object, if the caller is in the same context as that object.

System_CAPS_pubmethodSystem_CAPS_static GetComInterfaceForObject(Object, Type)

Returns a pointer to an IUnknown interface that represents the specified interface on the specified object. Custom query interface access is enabled by default.

2. But this link is promising

As it shows basically how to get to a PSObject (or basically to any object when you read the getPSType function)

https://github.com/Microsoft/ProtocolTestFramework/blob/master/src/testtools/Adapters/Script/PowerShellAdapterProxy.cs

//get the real object from the PSObject
                    realObject = psObject.InvokeMember(
                        "ImmediateBaseObject", 
                        BindingFlags.GetProperty,
                        null,
                        psPipelineObject, 
                        null);

                    //get the real type informations from the PSObject
                    Collection<string> typeNames = 
                        ((Collection<string>)psObject.InvokeMember(
                            "TypeNames", 
                            BindingFlags.GetProperty, 
                            null,
                            psPipelineObject, 
                            null));

so made this

 

func getReflectedObject($strAssembly, $strTypeName)
    Local $oAssembly = _CLR_LoadLibrary($strAssembly)
    Local $ptReflectedObject = 0
    $oAssembly.GetType_2($strTypeName, $ptReflectedObject)
    Local $oReflectedObject = ObjCreateInterface($ptReflectedObject, $sIID_IType, $sTag_IType)

;~  ConsoleWrite("$oAssembly: " & IsObj($oAssembly) & @CRLF)
;~  ConsoleWrite("$pAssemblyType = " & Ptr($ptReflectedObject) & @CRLF)
;~  ConsoleWrite("IsObj( $oAssemblyType ) = " & IsObj($oReflectedObject) & @TAB & @CRLF)

    return $oReflectedObject
endfunc

then just used like

local $oPSObject=getReflectedObject("System.Management.Automation", "System.Management.Automation.PSObject")
    local $oCollPSObject=getReflectedObject("System.Management.Automation", "System.Management.Automation.PSDataCollection`1")

Then expected it to work like this (But unfortunately I get nothing back)

local $countthem=0
    $oPSObject.InvokeMember_3("Count", 0x158, 0, 0, $objPsCollection, $countthem)

 

post 283 has the base example5 with the $objPSCollection (collection of PSObjects)

https://www.autoitscript.com/forum/topic/187334-using-net-libary-with-autoit-possible/?do=findComment&comment=1356513

Example5() ; System.Management.Automation

;~  local $oMarshal = getMarshal()
;~     ConsoleWrite("IsObj( $oMarshal ) = " & IsObj($oMarshal) & @TAB & @CRLF)

;~  local $pData
;~     $oMarshal.InvokeMember_3("SizeOf", 0x158, 0, 0, $oMarshal, $pData)
;~  ConsoleWrite("IsObj( $oMarshal data) = " & $pData & @TAB & @CRLF)
func getMarshal()
    Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    Local $ptMarshal = 0
    $oAssembly.GetType_2("System.Runtime.InteropServices.Marshal", $ptMarshal)
    Local $oMarshal = ObjCreateInterface($ptMarshal, $sIID_IType, $sTag_IType)

 ConsoleWrite("$oAssembly: " & IsObj($oAssembly) & @CRLF)
 ConsoleWrite("$pAssemblyType = " & Ptr($ptMarshal) & @CRLF)
 ConsoleWrite("IsObj( $oMarshal ) = " & IsObj($oMarshal) & @TAB & @CRLF)

    return $oMarshal
endfunc

Func Example5()
    Local $oAssemblyCore = _CLR_LoadLibrary("mscorlib")
    Local $oAssembly = _CLR_LoadLibrary("System.Management.Automation")
    local $oActivator=getActivator()
    local $oPSObject=getReflectedObject("System.Management.Automation", "System.Management.Automation.PSObject")
    local $oCollPSObject=getReflectedObject("System.Management.Automation", "System.Management.Automation.PSDataCollection`1")

;~ local $oMarshal = getMarshal()
;~     ConsoleWrite("IsObj( $oMarshal ) = " & IsObj($oMarshal) & @TAB & @CRLF)

;~  local $pData
;~     $oMarshal.InvokeMember_3("SizeOf", 0x158, 0, 0, $oMarshal, $pData)
;~  ConsoleWrite("IsObj( $oMarshal data) = " & $pData & @TAB & @CRLF)
    ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)
    ConsoleWrite("!$oAssemblyCore: " & IsObj($oAssemblyCore) & @CRLF)
;~     ConsoleWrite("!$oMarshal: " & IsObj($oMarshal) & @CRLF)



    ; Create Object
    Local $pAssemblyType = 0
    $oAssembly.GetType_2("System.Management.Automation.PowerShell", $pAssemblyType)
    ConsoleWrite("$pAssemblyType = " & Ptr($pAssemblyType) & @CRLF)

    Local $oActivatorType = ObjCreateInterface($pAssemblyType, $sIID_IType, $sTag_IType)
    ConsoleWrite("IsObj( $oAssemblyType ) = " & IsObj($oActivatorType) & @TAB & @CRLF)

    ; Create Object
    Local $pObjectPS = 0
    $oActivatorType.InvokeMember_3("Create", 0x158, 0, 0, 0, $pObjectPS)
    ConsoleWrite("IsObject: " & IsObj($pObjectPS) & @TAB & "$pObject: " & ObjName($pObjectPS) & @CRLF)

;~    https://github.com/PowerShell/PowerShell/issues/2291
;~      ps.AddScript("Get-Process | Out-String");
;~         var result = ps.Invoke()[0];
;~             Console.WriteLine(result.ToString());

    $pObjectPS.AddCommand("Get-Process") ; <<<<<<<<<<<<<< PS COMMAND HERE <<<<<<<<<<<<<<
;~      $pObjectPS.AddCommand("Out-String") ; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-string?view=powershell-3.0

$pObjectPS.AddScript("Get-Process | Out-String");

;~     $pObjectPS.AddCommand("Write-Output " & chr(34) & "Done" & chr(34)) ; <<<<<<<<<<<<<< PS COMMAND HERE <<<<<<<<<<<<<<
;~  $pObjectPS.AddCommand("Out-Host") ; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-string?view=powershell-3.0
;~  $pObjectPS.AddScript("foreach { $_.Name }") ; https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-string?view=powershell-3.0
    
    
    $objAsync = $pObjectPS.BeginInvoke()
    ConsoleWrite("$objAsync " & IsObj($objAsync & @TAB & "$pObject: " & ObjName($objAsync) ) & @CRLF)
    local $objPsCollection=getReflectedObject("System.Management.Automation","System.Management.Automation.PSDataCollection`1")
    $objPsCollection = $pObjectPS.EndInvoke($objAsync)

;~  Debug
    ConsoleWrite("$objPsCollection: " & IsObj($objPsCollection) & @TAB & "$objPsCollection: " & ObjName($objPsCollection) & " - " & ObjName($objPsCollection,6) & " - " & ObjName($objPsCollection,3)  & @CRLF)
    consolewrite("Count: " & @CRLF)
    local $countthem=0
    $countthem=$oCollPSObject.InvokeMember_3("Count", 0x158, 0, 0, $objPsCollection, 0)
;~  $oPSObject.InvokeMember_3("ToString", 0x158, 0, 0, $objPsCollection, $countthem)
    consolewrite("Count: " & $countthem & @CRLF)

;~  $objPsCollection.invokeMember_3("ToString", 0x158,0,0,0,0)
    ;~  get the real object from the PSObject
;~     local $realObject = 0
;~  $pObjectPS.InvokeMember_3("ImmediateBaseObject", $GetProperty, 0, 0,0,   $realObject);
;~  $pObjectPS.InvokeMember_3("ToString", $GetProperty, 0, 0,0,   $realObject);
;~     $oType = ObjCreateInterface($objPsCollection, $sIID_IType, $sTag_IType)
;~      ConsoleWrite("IsObj( $oType ) = " & IsObj($oType) & @CRLF)
;~     $oType.get_FullName($sFullName)
;~  ConsoleWrite("+TypeName = " & $sFullName & @CRLF)

;~  consolewrite($objPSCollection.ToString())
    
;~    ConsoleWrite("$objPsCollection: " & IsObj($realObject) & @TAB & "$objPsCollection: " & ObjName($realObject) & " - " & ObjName($realObject,6) & " - " & ObjName($realObject,3)  & @CRLF)



;~     local $pDispatch
;~     $oMarshal.InvokeMember_3("GetIDispatchForObject", 0x158, 0, 0, $objPsCollection, $pDispatch)
;~     $oMarshal.InvokeMember_3("GetIDispatchForObject", 0x158, 0, 0, $objPsCollection, $pDispatch)
;~ ConsoleWrite("IsObj( $oAssemblyType to string) = " & $pDispatch & @TAB & @CRLF)

;~  consolewrite($objPsCollection)
;~     Local $oColl 
;~     $objPSCollection.Unwrap($oColl)
;~  ConsoleWrite("IsObj($oColl): " & IsObj($oColl) & @CRLF)
        
;~     Local $pColls = $objPsCollection
;~     ConsoleWrite("$pColls = " & Ptr($pColls) & @CRLF)
;~     Local $iDim = SafeArrayGetDim($pColls)
;~     ConsoleWrite("$iDim = " & $iDim & @CRLF)

;~ AccVars_SafeArrayToArray( $pColls, $aObject ) ;  <<<<<<<<<<<<<<<<<<<<< Create SafeArray <<<<<<<<<<<<<<<<<<<<
    
;~  Local $vt = 0
;~     SafeArrayGetVartype($objAsync, $vt)
;~     ConsoleWrite("$vt = " & $vt & @CRLF)

EndFunc

 

Link to comment
Share on other sites

I played weeks / Months with it and it does not work whatever I tried.

It has to do something with this as well :

Quote

Important to know that CLR PowerShell Host runs in MTA Mode !!

Read more here : https://blogs.msdn.microsoft.com/powershell/2007/03/23/thread-apartmentstate-and-powershell-execution-thread/

 

The COM threading model is called an "apartment" model, where the execution context of initialized COM objects is associated with either a single thread (Single Thread Apartment) or many threads (Multi Thread Apartment). In this model, a COM object, once initialized in an apartment, is part of that apartment for the duration of its runtime.

The STA model is used for COM objects that are not thread safe. That means they do not handle their own synchronization. A common use of this is a UI component. So if another thread needs to interact with the object (such as pushing a button in a form) then the message is marshalled onto the STA thread. The windows forms message pumping system is an example of this.

If the COM object can handle its own synchronization then the MTA model can be used where multiple threads are allowed to interact with the object without marshalled calls.

Hopefully someone can proof the contrary...

Link to comment
Share on other sites

  • Powershell output just should be possible on everything I read on the internet just having a hard time to write it in AutoIt
    And piece of cake in C#
     
  • And a link in testcomplete different scripting languages showing that it should work

https://support.smartbear.com/testcomplete/docs/testing-with/advanced/using-external-functions/running-powershell-scripts.html

Sub Test
  Dim PowerShell, colEvents, oEvent, i

  Set PowerShell = dotNET.System_Management_Automation.PowerShell.Create

  Call powerShell.AddScript("get-eventlog system -entrytype (""Error"", ""Warning"") -newest 10")
  Set colEvents = powerShell.Invoke

  For i = 0 To colEvents.Count -1
    Set oEvent = colEvents.Item(i).ImmediateBaseObject

    Call Log.AppendFolder("Source: " & oEvent.Source)
    Call Log.Message("Type: " & oEvent.EntryType)
    Call Log.Message("Time: " & oEvent.TimeGenerated)
    Call Log.Message("Index: " & oEvent.Index)
    Call Log.Message("InstanceID: " & oEvent.InstanceID)
    Call Log.Message("MachineName: " & oEvent.MachineName)
    Call Log.Message("Message: (See Additional Info)", oEvent.Message)
    Call Log.Message("UserName: " & aqConvert.VarToStr(oEvent.UserName))
    Call Log.Message("EventID: " & oEvent.EventID)
    Call Log.PopLogFolder
  Next
End Sub
  • And a link with an alternative 

https://learn-powershell.net/2016/11/28/yet-another-way-to-get-output-from-a-runspace-reflection-edition/

#Specfiy the required flags to pull the output stream
$Flags = 'nonpublic','instance','static'
$Output = $PowerShell.GetType().GetProperty('OutputBuffer',$Flags)
  • Will download Testcomplete and do a try
Link to comment
Share on other sites

Some nice examples... but notice that 90% of all examples posted on the internet use the INVOKE method !

Which I can't get to run in AU3 ? So I had to move to the BEGININVOKE method. Which runs fine all over the line tested a lot of scenario's in AU3. 

So very happy with this one, ONLY we can't get any OUTPUT returned from the PSOBJECT ? 

The main difference is that this method is an ASYNC method that is fired, and the return TYPE is not a PSCOLLECTION, but an IAsyncResult  !

So we are talking about a different ballgame here, we can't mix the 2 approaches apparently.

SOLUTION :

Is to get the INVOKE method working in CLR, OR gettting output returned properly for the BEGININVOKE method.

So even if you get the Testcomplete working in VBScript .

It is of no use now, because we can't get the INVOKE method working (yet) in CLR. Which is very strange because that both are the same TYPE of Objects only the return TYPE is different. CLR is always complaining that it does not find a method with the name INVOKE ?

Link to comment
Share on other sites

Trying to summarize

The base logic is more or less (but for me I do not fully understand how to handle this in AutoIt whereas in C# this goes directly fine, could also be wrong in CLR.AU3 interface definitions)

  • When COM visible you can use dot syntax directly (nice example is getting the powershell main class)
  • Otherwise 
    $oPSObject.InvokeMember_3("Count", 0x158, 0, 0, $objPsCollection, $countthem)
    where the 0x158 depends on if you want to do a invokemethod or getproperty (as you defined nicely in the clr constants.au3). So above one is wrong value 0x158 and should be $property_get constant (still then it does not work ;-))
     
  • This gives me both a PSCollection and an ASyncResult
    $objPsCollection = $pObjectPS.EndInvoke($objAsync)

    But $objPSColleciton is represented as a System.Object which I probably have to CAST and no clue how to do that in AutoIt or even how to get to the first item in the collection returned (which I can create myself also as we did for many .NET classes, _CLR_CreateObject will probably do the same)

    local $oCollPSObject=getReflectedObject("System.Management.Automation", "System.Management.Automation.PSDataCollection`1")
  • BeginInvoke/EndInvoke deliver same result as Invoke (but to be 100% sure will try both in HP UFT and Testcomplete).
    But indeed weird we cannot call the INVOKE in AutoIt whereas BeginInvoke/EndInvoke do not give an issue (maybe wrong PSVersion loaded)

Our base problem: When a method returns an .NET object how to get to the methods/properties of it (when they are not COM visible). PSCollection is just an example.
So getting the powershell object is not that difficult but then later when the EndInvoke returns the .NET class collection it gets problematic whereas it should be a straight forward thing as shown in VBScript testcomplete and C#.

; Create Object
    Local $pAssemblyType = 0
    $oAssembly.GetType_2("System.Management.Automation.PowerShell", $pAssemblyType)
    Local $oActivatorType = ObjCreateInterface($pAssemblyType, $sIID_IType, $sTag_IType)

    Local $pObjectPS = 0
    $oActivatorType.InvokeMember_3("Create", 0x158, 0, 0, 0, $pObjectPS)

; Directly have a COM accessible object in AutoIt (no unwrapping, no objcreateinterface needed, no invokemethod_3 needed, no oActivator)
    $pObjectPS.AddCommand("Get-Process") ; <<<<<<<<<<<<<< PS COMMAND HERE <<<<<<<<<<<<<<

 

@Danyfirex can probably not help as I see in other thread he has a broken finger :(

 

Link to comment
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
 Share

×
×
  • Create New...