Jump to content

Transfer DllStruct between scripts


ramadash
 Share

Recommended Posts

on post 2 you will find functions to remotly call the call() functions with unlimited parameters.

hey all, this is the first script I post here :P I hope it meet's the requirements to post in this forum (as i didnt see any rules stickyed I assume that its ok).

I would first like to thank's Nomad for his nice memory include (you need it also) find it here: http://www.autoitscript.com/forum/index.ph...st&p=201269

At first I was looking at a way to transfer data btw scripts, I found a couple of ways, but now I needed a function to remotly call an internal function from a plugin .au3. Well this works so far, I don't think it can lead to an UDF because that it would need to be implemented in each script differently depending on the usage you want to do with it.

This is designed to eventually use the CALL() function with CallArgs array to pass random parameters to functions. But im sure that alot of other uses could be found for this. (the API call to sendmessage is the only thing I found to transfer data and it only support 2 params, and it dosent even support strings) so wich this you can pass as much params as you want using only 1 SendMessage.

ill try to make better explanations im not very good with english.

ok what this script does:

-Main.exe will idle (you need to run it first)

-When plugin.exe is lauched, it will create the structure defined in the source and send Remote_Function call to main.exe and pass the pointer adress of the struct to it

-when main.exe receive the message, it will open the memory of plugin.exe, create a new structure that is the same size as set by plugin in "HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01" (dont worry it gets deleted when the operation is done), it will then read the memory at the passed pointer and copy it at the newly created structure pointer.

ok so basically it just copy the struct lol.. I havent been able to get a pointer for the structure create in main, no clue why, but I had to use byref to set a struct.

ok so now the source, please give me feedbacks! I will also update this frequently

-plugin.au3 (this is the file that need's editing)

global $StructTypeString = "int;char[128];int;int";set the structure types here
global $STRUCT = DllStructCreate( $StructTypeString )
DllStructSetData( $STRUCT, 1, 555 );set the structure values here
DllStructSetData( $STRUCT, 2, "this is a string" )
DllStructSetData( $STRUCT, 3, 777 )
DllStructSetData( $STRUCT, 4, 888 )

;No editing needed below this point
RemoteFunc( WinGetHandle("myTest"), 10000, DllStructGetPtr( $STRUCT ), $StructTypeString )

Func RemoteFunc($window, $functionID, $wparam = 0, $lparam = 0)
    $dll = DllOpen("user32.dll")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01", "REG_SZ", $StructTypeString);dont worry this gets deleted after the call
    DllCall($dll, "none", "SendMessage","hwnd", $window, _
        "int", $functionID, "ptr",  $wparam, "str", $lparam)
    DllClose( $dll )
    $STRUCT = 0
    exit 
EndFunc

-main.au3

#include <GUIConstants.au3>
#include <memory.au3>
;Editing of this file is not needed ( well except if you want to add features )
global $memHANDLE, $StructTypeString 

$CMD_Test = 10000
$mygui = GuiCreate("myTest",1,1)
GUIRegisterMsg($CMD_Test, "Rebuild_Struct")

func Rebuild_Struct($hWndGUI, $MsgID, $ptr, $useless )
    $StructTypeString = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01")
    dim $v_buffer
    $memHANDLE = OpenMem( "Plugin.exe" )
     _MemoryGetStruct( $ptr , $memHandle, $v_buffer, $StructTypeString  ) 
    $fooError = @error 
    if $fooError > 0 then
        MsgBox( 0, "", "Error reading memory, @error= " & $fooError & " " & $StructTypeString )
        exit 
    EndIf
    $MaxIndex = StringSplit( $StructTypeString, ";" )
    dim $debugString
    for $i = 1 to $MaxIndex [0]
        $debugString &= " " & DllStructGetData( $v_buffer, $i )
    Next
    MsgBox( 0, "", $debugString )
    $v_buffer = 0;free mem used by struct
    _MemoryClose( $memHANDLE )
    if @error then MsgBox( 0, "", "Error closing memory" )
    Regdelete("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01" )
    exit 
EndFunc


While 1
    Sleep(100)
WEnd

;return a memory handle
func OpenMem( $process )
    $pid = ProcessExists ( $process )
    if not $pid then 
        MsgBox( 0, "", "ERROR: " & $process & " process does not exist" )
        exit 
    EndIf

;open main memory handle
    $mem = _memoryOpen( $pid )
    $fooError = @error
    if $fooError > 0 then 
        MsgBox( 0, "", "error opening " & $process & " , @error=" & $fooError )
        Exit
    Else
        MsgBox( 0, "", $process & " memory open sucessfully" )
    EndIf
    return $mem
EndFunc

;based off Nomad _MemoryRead() functions, credits to him :D 
;using byref is the only way I was able to keep the struct valid outside the function
;error values are the same as _MemoryRead()
;return value, 1=sucess 0=failed
func _MemoryGetStruct( $iv_Address, $ah_Handle, byref $v_buffer, $sv_Type = 'dword' )
    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf
    
    $v_Buffer = DllStructCreate($sv_Type)
    
    If @Error Then
        SetError(@Error + 1)
        Return 0
    EndIf
    
    DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
    
    If Not @Error Then
        return 1
    Else
        SetError(6)
        Return 0
    EndIf
    
EndFunc
Edited by ramadash
Link to comment
Share on other sites

the following scripts will wrap the call() function so it can be called from a run /autoitexec "myscript" (virtually giving all functions in the main script to the executed script)

what this will do (compile them and run main first for an example) :

1. Main.exe get's loaded first, this script hold all the functions

2. When you load Plugin.exe, it will send a message to Main.exe, telling it to execute the specified functions (see top of plugin.au3)

3. Main.exe will execute the functions

4. Plugin.exe will close main.exe after all functions are executed

-main.au3

#include <GUIConstants.au3>
#include <memory.au3>
#include <array.au3>

;EXAMPLE FUNCTIONS 
func msgbox1($var1, $var2, $var3, $var4)
    MsgBox( 0, "", "MsgBox1(): " & $var1 & " " & $var2 & " " & $var3 & " " & $var4 ) 
EndFunc
func msgbox2($var1,$var2)
    MsgBox( 0, "", "MsgBox2(): " & $var1 & " " & $var2 )
EndFunc
func MsgBox3( $OneVar )
    MsgBox( 0, "", "MsgBox3(): This function have only 1 variable, this variable is: " & $onevar )
EndFunc
func msgbox4()
    MsgBox( 0, "", "MsgBox4(): This function have no parameters passed to it" )
EndFunc


#region call function wrapper (server)
;Editing of this file is not needed ( well except if you want to add features )

$CMD_CallWrapper = 10000
$CMD_Quit = 10001
$mygui = GuiCreate("myTest",1,1)
GUIRegisterMsg($CMD_CallWrapper, "CallWrapper" )
GUIRegisterMsg( $CMD_Quit, "Quit" )

While 1
    Sleep(100)
WEnd

func Quit()
    Exit
EndFunc

;TODO get rid of regread (yes im lazy...) - handle errors with setting @error instead of msgbox-exit 
func CallWrapper($hWndGUI, $MsgID,  $ptr, $args )
    switch $args
    case 0
        call ( RegRead( "HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1" ) )
        RegDelete("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1")
    case 1
        $arg = StringSplit( RegRead( "HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1" ) , "." )
        RegDelete( "HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1" )
        call ( $arg[1], $arg[2] )
    case 2
        $StructTypeString = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01")
        Regdelete("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01" )
        dim $v_buffer
        $memHANDLE = OpenMem( "Plugin.exe" )
        _MemoryGetStruct( $ptr , $memHandle, $v_buffer, $StructTypeString  ) 
        $fooError = @error 
        if $fooError > 0 then
            MsgBox( 0, "", "Error reading memory, @error= " & $fooError & " " & $StructTypeString )
            exit 
        EndIf
        $MaxIndex = StringSplit( $StructTypeString, ";" )       
        $funcName = DllStructGetData( $v_buffer, $MaxIndex[0] )
        dim $fooArgs[  $MaxIndex[0]   ]
        for $i = 0 to $maxindex[0] -1
            $fooArgs[ $i ] = DllStructGetData( $v_buffer, $i+1 )
        Next
        _ArrayPop( $fooArgs )
        call ( $funcName, $fooArgs )
        if @error then 
            MsgBox( 0, "", "Function " & $funcName & " does not exist" )
        EndIf
        $v_buffer = 0;free mem used by struct
        _MemoryClose( $memHANDLE )
        if @error then MsgBox( 0, "", "Error closing memory" )
    EndSwitch
EndFunc

;return a memory handle
func OpenMem( $process )
    $pid = ProcessExists ( $process )
    if not $pid then 
        MsgBox( 0, "", "ERROR: " & $process & " process does not exist" )
        exit 
    EndIf
;open main memory handle
    $mem = _memoryOpen( $pid )
    $fooError = @error
    if $fooError > 0 then 
        MsgBox( 0, "", "error opening " & $process & " , @error=" & $fooError )
        Exit
    EndIf
    return $mem
EndFunc

;based off Nomad _MemoryRead() functions, credits to him :D 
;using byref is the only way I was able to keep the struct valid outside the function
;error values are the same as _MemoryRead()
;return value, 1=sucess 0=failed
func _MemoryGetStruct( $iv_Address, $ah_Handle, byref $v_buffer, $sv_Type = 'dword' )
    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf
    
    $v_Buffer = DllStructCreate($sv_Type)
    
    If @Error Then
        SetError(@Error + 1)
        Return 0
    EndIf
    
    DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
    
    If Not @Error Then
        return 1
    Else
        SetError(6)
        Return 0
    EndIf
    
EndFunc

#endregion

-plugin.au3

;supports STRING and INT ->ONLY<-

global $MainWindowName = "myTest"

; call --> msgbox1($var1, $var2, $var3, $var4)
dim $arg1[4] = [ "var1", "var2", "var3", "var4" ]
CallFunction ( "msgbox1", $arg1 )

;call --> msgbox2($var1,$var2)
dim $arg2[2] = [ 1, " previous arg was an integer" ]
CallFunction ( "msgbox2", $arg2 )

;call --> MsgBox3( $OneVar ) 
CallFunction ( "MsgBox3" , "yahooo" )

;call --> MsgBox4()
CallFunction( "MsgBox4" )

RemoteFunc( WinGetHandle( $MainWindowName ), 10001 );kill main.exe

#region call function wrapper (client)
func CallFunction( $FuncName, $args = 0 )
    if $args == 0 then 
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1", "REG_SZ", $FuncName )
        RemoteFunc( WinGetHandle( $MainWindowName ), 10000, 0, 0 )
        Return
    elseif IsArray($args) == 0 then 
        RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "Param1", "REG_SZ", $FuncName & "." & $args)
        RemoteFunc( WinGetHandle( $MainWindowName ), 10000, 0, 1 )
        return 
    Else
        local $StructTypeString= "char[13];", $Struct, $debugString
        for $var in $args
            if IsInt( $var ) then 
                $StructTypeString &= "int;"
            elseif IsString ( $var ) then               
                $StructTypeString &= "char[" & ( StringLen( $var ) + 1 ) & "];"
            Else
                MsgBox( 0, "", "Function() Error: " & $var & " is not an int and not a string" )
            EndIf
        Next
        $StructTypeString &=  "char[" & StringLen( $funcName ) + 1 & "]"
        $Struct = DllStructCreate( $StructTypeString )
        DllStructSetData( $Struct, 1, "CallArgArray" )
        for $i = 1 to UBound( $args ) 
            DllStructSetData(  $Struct, $i+1, $args[$i-1] )
        next 
        DllStructSetData( $Struct, Ubound( $args ) + 2, $funcName )
        RemoteFunc( WinGetHandle( $MainWindowName ), 10000, DllStructGetPtr( $Struct ), 2, $StructTypeString )
    EndIf
EndFunc

Func RemoteFunc($window, $functionID, $wparam = 0, $lparam = 0, $StructTypeString = "")
    $dll = DllOpen("user32.dll")
    RegWrite("HKEY_LOCAL_MACHINE\SOFTWARE\autoit3", "StructTypeString01", "REG_SZ", $StructTypeString);dont worry this gets deleted after the call
    DllCall($dll, "none", "SendMessage","hwnd", $window, _
        "int", $functionID, "ptr",  $wparam, "int", $lparam)
    DllClose( $dll )
    $STRUCT = 0
EndFunc
#endregion
Link to comment
Share on other sites

  • 3 months later...
  • 2 weeks later...

I tried it and found it impressive as a proof of concept.

How I, personally, would use it is a little less clear, but that's just my situation.

I don't suppose you've tried sharing COM objects between scripts? That could be insanely useful when used with a Dictionary or SortedList object.

Link to comment
Share on other sites

  • 3 months later...

There are also some blocking issues. What if the user use sleep in one of the functions?

But all in all, nice sample...:shocked:

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...