granstrom

Issues with COM Object Method with Pointer based Arguments

9 posts in this topic

I'm working on translating a COM object based VBScript to AutoIt script and I'm having issues with several methods that use pointers to variants as agruments. Right now I'm using a workaround of running the vbscript below with the ScriptControl COM wrapper, but I'd rather rewrite it natively in AutoIt if that's possible.

The piece of code I'm trying to translate is (found here):

Sub EnumerateUpdates()

    ' Initialize variables.
    dim updatesDeployment
    dim progress
    dim updateCount
    dim update
    dim progressStage
    dim percentComplete
    dim errorCode
    dim updateData
    dim notify

    ' Create an UpdatesDeployment instance.
    set updatesDeployment = CreateObject ("UDA.CCMUpdatesDeployment")

    ' Get the current updates.
    Set updatesColl = updatesDeployment.EnumerateUpdates( 2, 0, progress )

    ' Get a count of the current updates.
    updateCount = updatesColl.GetCount()


    ' Determine whether there are any updates to enumerate.
    if updatecount = 0 then
    
        WScript.echo "No updates found."
        
    else
        
        ' Loop through the updates.
        for nIndex = 0 To updateCount-1

            Set update = updatesColl.GetUpdate(nIndex)

            WScript.echo "Update ID: " & update.GetId()
            if update.GetEnforcementDeadline() <> Null then
                 WScript.echo "Enforcement Deadline: " & update.GetEnforcementDeadline()
            else
                 WScript.echo "Enforcement Deadline: None" 
            end if 
            WScript.echo "Bulletin ID: " & update.GetBulletinId()
            WScript.echo "Article ID: " & update.GetArticleId()
            WScript.echo "Name: " & update.GetName(1033)
            WScript.echo "Summary: " & update.GetSummary(1033)
            WScript.echo "Information Link: " & update.GetInfoLink(1033)
            WScript.echo "Manufacturer: " & update.GetManufacturer(1033)
            WScript.echo "State: " & update.GetState()

            update.GetProgress progressStage, percentComplete, errorCode
            
            WScript.echo "Progress Stage: " & progressStage
            WScript.echo "Percent Complete: " & percentComplete
            WScript.echo "Error Code: " & errorCode
            
            WScript.echo "Notification Option: " & update.GetNotificationOption()
            WScript.echo " "

        next

    end if
    
End Sub

The specific line that doesn't seem to be working is:

update.GetProgress progressStage, percentComplete, errorCode

When run using the vbscript example, the progressStage variable returns an integer between 0 and 16. When run using an AutoIt script I get a null string.

That method is defined here: here

[iDL]

HRESULT GetProgress(

VARIANT* pvarUpdateStatus,

VARIANT* pvarPercentComplete,

VARIANT* pvarError

);

I've tried using dllstructcreate() to initialize a struct, then using dllstructgetptr() to pass the ptr for each of the arguments in that GetProgress method and still don't see any return value.

Can anyone provide any guidance on how to deal with that type of COM method?

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

The code that doesn't work after conversion to AutoIt looks like this:

Func EnumerateUpdates()

    ' Initialize variables.
    dim $updatesDeployment
    dim $progress
    dim $updateCount
    dim $update
    dim $progressStage
    dim $percentComplete
    dim $errorCode
    dim $updateData
    dim $notify
    dim $output

    ' Create an UpdatesDeployment instance.
    $updatesDeployment = ObjCreate("UDA.CCMUpdatesDeployment")

    ' Get the current updates.
    $updatesColl = $updatesDeployment.EnumerateUpdates( 2, 0, $progress )

    ' Get a count of the current updates.
    $updateCount = $updatesColl.GetCount()


    ' Determine whether there are any updates to enumerate.
    if $updatecount = 0 then
    
        $output = "No updates found."
        
    else
        
        ' Loop through the updates.
        for $nIndex = 0 To $updateCount-1

            $update = $updatesColl.GetUpdate(nIndex)

            $output = $output & @CRLF & "Update ID: " & $update.GetId()
            if $update.GetEnforcementDeadline() <> "" then
                 $output = $output & @CRLF & "Enforcement Deadline: " & $update.GetEnforcementDeadline()
            else
                 $output = $output & @CRLF & "Enforcement Deadline: None" 
            endif 
            $output = $output & @CRLF & "Bulletin ID: " & $update.GetBulletinId()
            $output = $output & @CRLF & "Article ID: " & $update.GetArticleId()
            $output = $output & @CRLF & "Name: " & $update.GetName(1033)
            $output = $output & @CRLF & "Summary: " & $update.GetSummary(1033)
            $output = $output & @CRLF & "Information Link: " & $update.GetInfoLink(1033)
            $output = $output & @CRLF & "Manufacturer: " & $update.GetManufacturer(1033)
            $output = $output & @CRLF & "State: " & $update.GetState()

            $update.GetProgress $progressStage, $percentComplete, $errorCode
            
            $output = $output & @CRLF & "Progress Stage: " & $progressStage
            $output = $output & @CRLF & "Percent Complete: " & $percentComplete
            $output = $output & @CRLF & "Error Code: " & $errorCode
            
            $output = $output & @CRLF & "Notification Option: " & $update.GetNotificationOption()
            $output = $output & @CRLF & " "

        next

    endif
    Return $output
EndFunc
Edited by granstrom

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Looks like progressStage, percentComplete, and errorCode are ByRef.

AutoIt doesn't do ByRef with COM methods. It's a very old issue and I don't think it has changed yet.

:)

P.S. Ref BugTrack #134: Add support for COM events to take ByRef parameters

That's actually about a COM event, so I'm not sure if that's the right issue or not.

;)

AutoIt syntax requires the parens around the parameter values, so you could at least try it this way to see:

$update.GetProgress($progressStage, $percentComplete, $errorCode)

;)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

That would certainly explain the issue. ;) I guess I'll have to keep my eye on the change log to see if that functionality is added in the future. Thanks for the quick reply.

Share this post


Link to post
Share on other sites

Oops, yeah, those parens are there in the version of code that I'm compiling. I'll edit my post.

Share this post


Link to post
Share on other sites

Hello everybody

Is there any new information available regarding pointer based arguments with COM object methods in AutoIt?

My task is the following: The backup software StorageCraft ShadowProtect Desktop provides a VB scripting interface. You can find a couple of example scripts as well as some basic documentation here.

I now try to retrieve some status information of a running backup as shown in the following “BackupJobGetStatus.vbs”.

Set stdOut = WScript.Stdout
Set ShadowProtect = CreateObject ("ShadowStor.ShadowProtect")
StdOut.Write "Display backup job status" & vbCrLf & vbCrLf

Dim BackupJob, JobName, volumes
Dim status, totalTime, remainingTime, bytesPerSecond

ON ERROR RESUME NEXT

'REPLACE WITH VALID NAME
JobName="Auto NAS"
Set BackupJob = ShadowProtect.Jobs.GetBackupJob(JobName)

if Err<>0 then
    StdOut.Write "GetBackupJob failed for " & JobName & vbCrLf
else
    BackupJob.GetVolumes volumes
    if Err<>0 then
        StdOut.Write "GetVolumes failed" & vbCrLf
    else
        BackupJob.GetJobStatus status
        StdOut.Write "Job Status = " & status & vbCrLf & vbCrLf
        
        StdOut.Write "Volume(s):" & vbCrLf
        For Each Volume in volumes
            BackupJob.GetStatus Volume, status
            if Err<>0 then
                StdOut.Write "Unable to get volume status" & vbCrLf
            else
                StdOut.Write Volume & " status = " & status & vbCrLf
            end if

            BackupJob.GetRunningStatus Volume, totalTime, remainingTime, bytesPerSecond
            if Err<>0 then
                StdOut.Write "Unable to get running status" & vbCrLf
            else
                StdOut.Write "Running Statistics:" & vbCrLf
                StdOut.Write "  total time = " & totalTime & vbCrLf
                StdOut.Write "  time left = " & remainingTime & vbCrLf
                StdOut.Write "  bytes per second = " & bytesPerSecond & vbCrLf
            end if
            StdOut.Write  vbCrLf
        Next
    end if  
end if



'status values:
'
'    
'    init = 1       // created, not saved or executed
'    
'    initialized = 2    // created, saved and ready to execute
'    
'    queued = 3     // scheduled and waiting for being executed (first time)
'    
'    running = 4    // running
'    
'    aborting = 5   // cancelled but is running yet
'    
'    aborted = 6    // canceled and has finished processing
'    
'    failed = 7     // executed but failed and will not run next time again
'    
'    failedqueued = 8   // executed, failed and will run next time
'    
'    completed = 9  // executed and finished successfully
'    
'    completedqueued = 10 // executed, finished successfully and will run next time
'    
'    deleted = 11   // deleted, but has external locks
'    
'    expired = 12   // expired
'    
'    disabled = 13  // disabled

My problems already begin with implementing the method "GetBackupJob"

HRESULT GetBackupJob(

         [in] VARIANT Name,

         [out, retval] VARIANT *ppBackupJob

         );

The following AutoIt-Code gets me an ID but no more information about this backup job. All additional method-calls based on the selected backup job fail.

#RequireAdmin
#include <Array.au3>
#include <MsgBoxConstants.au3>

Local $BackupJob, $JobName, $volumes
Local $status, $totalTime, $remainingTime, $bytesPerSecond

$oShadow = ObjCreate("ShadowStor.ShadowProtect")

$JobName = "Auto NAS"

$BackupJob = $oShadow.Jobs.GetBackupJob($JobName)

MsgBox($MB_SYSTEMMODAL, "Job", "ID: " & $BackupJob.ID & @CRLF & _
                               "Desc: " & $BackupJob.Description & @CRLF & _
                               "Status: " & $BackupJob.Status & @CRLF & _
                               "Type: " & $BackupJob.Type & @CRLF)

Exit

Do you have any idea how to solve this problems?

Share this post


Link to post
Share on other sites

You need to add error checking to your code.

Easiest way is to add teh following lines at the top of your script.

#include <Debug.au3>
_DebugSetup()
_DebugCOMError()

This will display additional error information in a separate window.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

The message box only shows an ID information ({2B10D23C-566F-4FEE-AD1B-1B99F27F12A5}) but no additional information. Instead I receive the following error message.

@@ DEBUG COM Error encountered in BackupJobGetStatus.au3 (17) :
    Number          = 0x80020006 (-2147352570)
    WinDescription  = Unbekannter Name.
    Description     = 
    Source          = 
    HelpFile        = 
    HelpContext     = 
    LastDllError    = 0
    Retcode         = 0x00000000
@@ DEBUG COM Error encountered in BackupJobGetStatus.au3 (17) :
    Number          = 0x80020006 (-2147352570)
    WinDescription  = Unbekannter Name.
    Description     = 
    Source          = 
    HelpFile        = 
    HelpContext     = 
    LastDllError    = 0
    Retcode         = 0x00000000
@@ DEBUG COM Error encountered in BackupJobGetStatus.au3 (17) :
    Number          = 0x80020006 (-2147352570)
    WinDescription  = Unbekannter Name.
    Description     = 
    Source          = 
    HelpFile        = 
    HelpContext     = 
    LastDllError    = 0
    Retcode         = 0x00000000

Besides I tried different methods (e.g. GetJobName, GetJobComment) to receive the information. But with the same result. IMHO already the method call GetBackupJob($JobName) doesn't work properly.

Share this post


Link to post
Share on other sites

The message tell us that the method or property used in line 17 are unknown.

As you get the ID the object "BackupJob" seems to be ok.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

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