Jump to content

Object method with structure array as parameter

Go to solution Solved by Nine,

Recommended Posts

I am working on a UDF for Microsoft's BITS (Background Intelligent Transfer Service).
For this I use the AutoIt function ObjCreateInterface.
Now the method IBackgroundCopyJob::AddFileSet causes me problems, because I have no idea how to implement it in AutoIt.

For IBackgroundCopyJob::AddFile, the "little brother" of the previously mentioned method, it's easy - there my implementation looks like this:

Func _BITS_BackgroundCopyJob_AddFile(Const ByRef $oBackgroundCopyJob, Const ByRef $sRemoteUrl, Const ByRef $sLocalName)
    $oBackgroundCopyJob.AddFile($sRemoteUrl, $sLocalName)
EndFunc   ;==>_BITS_BackgroundCopyJob_AddFile

But how does it have to look for IBackgroundCopyJob::AddFileSet:

Func _BITS_BackgroundCopyJob_AddFileSet(Const ByRef $oBackgroundCopyJob, Const ByRef $iFileCount, Const ByRef $aFileSet)
    $oBackgroundCopyJob.AddFileSet($iFileCount, ???)
EndFunc   ;==>_BITS_BackgroundCopyJob_AddFileSet

For example, $aFileSet looks like this:

Local $aFileSet[][] = [["RemoteName1", "LocalName1"], ["RemoteName2", "LocalName2"], ["RemoteName3", "LocalName3"]]


Link to post
Share on other sites

Try something like this :

#include <WinAPIDiag.au3>

Local $aFileSet[][] = [["RemoteName1", "LocalName1"], ["RemoteName2", "LocalName2"], ["RemoteName3", "LocalName3"]]

Local $sStructDef

For $i = 0 To UBound($aFileSet) - 1
  $sStructDef &= "char r" & $i+1 & "[" & StringLen($aFileSet[$i][0])+1 & "];char l" & $i+1 & "[" & StringLen($aFileSet[$i][1])+1 & "];"

ConsoleWrite($sStructDef & @CRLF)

$tStruct = DllStructCreate($sStructDef)
For $i = 0 To UBound($aFileSet) - 1
  DllStructSetData($tStruct, "r" & $i+1, $aFileSet[$i][0])
  DllStructSetData($tStruct, "l" & $i+1, $aFileSet[$i][1])

_WinAPI_DisplayStruct($tStruct, $sStructDef)

$pStruct = DllStructGetPtr($tStruct)


Link to post
Share on other sites

@Nine, I tried to implement the method with your suggestion.
You can find the corresponding state of the UDF here: https://github.com/DonChunior/BITS-UDF/tree/AddFileSet

Unfortunately the code does not work: In the SciTE console the error message "AutoIt3.exe ended.rc:-1073741819" is displayed. 😕
Do you have any idea what could be the cause of the problem?

You could test the implementation of the AddFileSet method with the following sample code:

#include <BITS.au3>


Func Main()
    Local $oBackgroundCopyManager = _BITS_Connect()
    Local $oJob = _BITS_BackgroundCopyManager_CreateJob($oBackgroundCopyManager, "Test_Job", $BG_JOB_TYPE_DOWNLOAD)
    Local $aFileSet = [["http://ipv4.download.thinkbroadband.com/1GB.zip", "C:\Temp\1GB.zip"], ["http://ipv4.download.thinkbroadband.com/512MB.zip", "C:\Temp\512MB.zip"]]
    _BITS_BackgroundCopyJob_AddFileSet($oJob, $aFileSet)


Link to post
Share on other sites

So AutoIt3 is crashing...If it is not the actual strings then it must be pointers to string.  So the struct should be "ptr;ptr;ptr;ptr;" (for 2 sets).  Each pointer points to a string.

ps. I tested with my code and it is crashing passing actual strings.  But it is not crashing using ptr to string.  However when I resume the job, it doesn't start downloading...Maybe I am missing something.

Link to post
Share on other sites

Hello. Use LPWSTR.



Your struct should be an array of BG_FILE_INFO pointers.


I meant this in the @Nine's code:

Local $tBGFileInfo=DllStructCreate("ptr[" &  UBound($aFileSet)  & "]")
$tStruct = DllStructCreate($sStructDef)
For $i = 0 To UBound($aFileSet) - 1
  DllStructSetData($tStruct, "r" & $i+1, $aFileSet[$i][0])
  DllStructSetData($tStruct, "l" & $i+1, $aFileSet[$i][1])
  DllStructSetData($tBGFileInfo,1, DllStructGetPtr($tStruct,"r" & $i+1),$i+1)

Local $pStruct = DllStructGetPtr($tBGFileInfo)



Edited by Danyfirex
Add Code
Link to post
Share on other sites


I haven't looked through your whole bits.au3 udf file, but I do see one issue.  Your definition if the BG_FILE_INFO struct is not correct.  You aren't currently using it in your UDF but when/if you do, it will cause problems as it is currently defined.  It is currently defined as:

; BG_FILE_INFO structure (https://docs.microsoft.com/en-us/windows/win32/api/bits/ns-bits-bg_file_info)
Global Const $tagBG_FILE_INFO = "struct;wchar remoteName[2201];wchar localName[261];endstruct"

it should be something like:

Const $tagBG_FILE_INFO = _
          "struct; "        & _
          "ptr remoteName;" & _
          "ptr localName;"  & _


Below is a quick example that I created that will create an array of BG_FILE_INFO structs.  It is based on an interpretation of the AddFileSet example code from the Microsoft site.  It is commented pretty well but does not have any error checking.  It is just a quick script to show another way that the struct array can be created.  Because AutoIt does not make it easy to get pointer information of normally declared variables, the next best thing is to declare structs to hold the variables.  That will give you access to their pointers.  So as you will see, in order to get pointers to the remote and local names of the file set, I create an array of structs for the names.  Other than that, the code should be pretty straight forward.

I haven't tested it with your UDF.  I'll leave that part of the fun to you.  ;)

#AutoIt3Wrapper_AU3Check_Parameters=-w 3 -w 4 -w 5 -w 6 -d

#include <Constants.au3>
#include <WinAPIDiag.au3>
#include <Array.au3>

Const $gtagBG_FILE_INFO = _
          "struct; "        & _
          "ptr remoteName;" & _
          "ptr localName;"  & _

Global $gaFileSet = _
          [ _
          ["http://ipv4.download.thinkbroadband.com/1GB.zip",   "C:\Temp\1GB.zip"], _
          ["http://ipv4.download.thinkbroadband.com/512MB.zip", "C:\Temp\512MB.zip"] _

Global $gtBG_FILE_INFO_ARRAY = ""

$gtBG_FILE_INFO_ARRAY = get_bg_file_info_array_struct_example($gaFileSet)

_WinAPI_DisplayStruct( _
    StringFormat("ptr[%i]", UBound($gaFileSet) * 2), _
    "BG_FILE_INFO Array" _

Func get_bg_file_info_array_struct_example($aFileSet)

    Local $tBG_FILE_INFO = "", $tByteBuffer = "", $tBG_FILE_INFO_ARRAY = ""
    Local $iBG_FILE_INFO_SIZE = 0
    Local $pArrayItemPointer = 0
    Local $xWcharString = Binary("")
    Local $atRemoteNames[0], $atLocalNames[0]

    ;For each file set
    For $i = 0 To UBound($aFileSet) - 1
        ;Add remote name to array of remote name structs
        $xWcharString     = StringToBinary($aFileSet[$i][0], $SB_UTF16LE)
        $tByteBuffer      = DllStructCreate(StringFormat("byte data[%i];", BinaryLen($xWcharString)))
        $tByteBuffer.data = $xWcharString
        _ArrayAdd($atRemoteNames, $tByteBuffer)

        ;Add local name to array of local name structs
        $xWcharString     = StringToBinary($aFileSet[$i][1], $SB_UTF16LE)
        $tByteBuffer      = DllStructCreate(StringFormat("byte data[%i];", BinaryLen($xWcharString)))
        $tByteBuffer.data = $xWcharString
        _ArrayAdd($atLocalNames, $tByteBuffer)

    ;Create a bg_file_info struct to get size of struct
    $tBG_FILE_INFO      = DllStructCreate($gtagBG_FILE_INFO)
    $iBG_FILE_INFO_SIZE = DllStructGetSize($tBG_FILE_INFO)

    ;Create byte buffer to hold array of bg_file_info structs
    $tBG_FILE_INFO_ARRAY = DllStructCreate(StringFormat("byte buffer[%i]", $iBG_FILE_INFO_SIZE * UBound($aFileSet)))

    ;For each file set
    For $i = 0 To UBound($aFileSet) - 1
        ;Add a populated bg_file_info struct to the array of bg_file_info structs
        $pArrayItemPointer        = DllStructGetPtr($tBG_FILE_INFO_ARRAY) + ($iBG_FILE_INFO_SIZE * $i)
        $tBG_FILE_INFO            = DllStructCreate($gtagBG_FILE_INFO, $pArrayItemPointer)
        $tBG_FILE_INFO.remoteName = DllStructGetPtr($atRemoteNames[$i])
        $tBG_FILE_INFO.localName  = DllStructGetPtr($atLocalNames[$i])

    ;Sanity check - Display values from the bg_file_info array to make sure they were loaded properly
    For $i = 0 To UBound($aFileSet) - 1
        ;Point to bg_file_info struct item within the bg_file_info array
        $pArrayItemPointer = DllStructGetPtr($tBG_FILE_INFO_ARRAY) + ($iBG_FILE_INFO_SIZE * $i)
        $tBG_FILE_INFO     = DllStructCreate($gtagBG_FILE_INFO, $pArrayItemPointer)

        ;Get & display the remote name pointed to by the remote name pointer
        $tByteBuffer = DllStructCreate("byte data[1000];", $tBG_FILE_INFO.remoteName)
        ConsoleWrite(StringFormat("Remote name %2i = %s", $i + 1, BinaryToString($tByteBuffer.data, $SB_UTF16LE)) & @CRLF)

        ;Get & display the local name pointed to by the local name pointer
        $tByteBuffer = DllStructCreate("byte data[1000];", $tBG_FILE_INFO.localName)
        ConsoleWrite(StringFormat("Local  name %2i = %s", $i + 1, BinaryToString($tByteBuffer.data, $SB_UTF16LE)) & @CRLF)



Console output: (this output was just a sanity check for me to know that the information in the arrays were correct)

Remote name  1 = http://ipv4.download.thinkbroadband.com/1GB.zip
Local  name  1 = C:\Temp\1GB.zip
Remote name  2 = http://ipv4.download.thinkbroadband.com/512MB.zip
Local  name  2 = C:\Temp\512MB.zip


Edited by TheXman
Smalll cosmetic change to the script
Link to post
Share on other sites
  • Solution

TheXman code did not work for me.  Although this one is working perfectly fine :


Local $oBackgroundCopyJob = ObjCreateInterface($pJob, $sIID_IBackgroundCopyJob, $tagIBackgroundCopyJob)
  ConsoleWrite(VarGetType($oBackgroundCopyJob) & @CRLF)

  ;$oBackgroundCopyJob.AddFile("http://www.autoitscript.com/autoit3/files/beta/update.dat", @ScriptDir & "\Test.tmp")
  Local $aFile = [["http://ipv4.download.thinkbroadband.com/5MB.zip", @ScriptDir & "\Test1.zip"], _
                  ["http://www.autoitscript.com/autoit3/files/beta/update.dat", @ScriptDir & "\Test2.txt"]]

  AddFileSet($oBackgroundCopyJob, $aFile)

Func AddFileSet(ByRef $obj, ByRef $aFileSet)
  Local $sStructDef = _StringRepeat("ptr;", UBound($aFileSet) * 2)
  Local $tStruct = DllStructCreate($sStructDef)
  Local $tFileInfo1[UBound($aFileSet)], $tFileInfo2[UBound($aFileSet)]
  For $i = 0 to UBound($aFileSet) - 1
    $tFileInfo1[$i] = DllStructCreate("wchar[" & StringLen($aFileSet[$i][0]) + 1 & "];")
    $tFileInfo2[$i] = DllStructCreate("wchar[" & StringLen($aFileSet[$i][1]) + 1 & "];")
    DllStructSetData($tFileInfo1[$i], 1, $aFileSet[$i][0])
    DllStructSetData($tFileInfo2[$i], 1, $aFileSet[$i][1])
    DllStructSetData($tStruct, $i*2+1, DllStructGetPtr($tFileInfo1[$i]))
    DllStructSetData($tStruct, $i*2+2, DllStructGetPtr($tFileInfo2[$i]))
  _WinAPI_DisplayStruct($tStruct, $sStructDef)
  $obj.AddFileSet(UBound($aFileSet), $tStruct)


Edited by Nine
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...