Welcome to the SRP Forum! Please refer to the SRP Forum FAQ post if you have any questions regarding how the forum works.

SRP_COM 64 bit

Hi

Last year I had problems with SRP_COM and WORD automation in OI10.2.0. I saw a new release of SRP Utilities and thought this may fix it.

However, I still get an error 80020005 whenever I attempt the following:
oSaveAs = SRP_Com(oDocHandle2, "CALL", "SAVEAS2", pdfName, wdFormatPDF$)
where pdfName = "foo.pdf" and wdFormatPDF$ = 17

oPrintOut = SRP_Com(oDocHandle2, "CALL", "PRINTOUT",wdBackground$)
where wdBackground$ = 0

As a matter of interest, the corresponding OI10.2.1 OLE functions fail as well.

Thanks

Comments

  • edited February 7
    You'll need to use the BEGINCALL, ADDPARAM, and ENDCALL services to do this. Word OLE Automation must be expressly told when a parameter is omitted. Simply omitting them in a CALL service isn't sufficient.

    Using your example, the SAVEAS2 call would like something like this (Note: I didn't test this in Word or anything):

    SRP_Com('', 'BEGINCALL') SRP_Com('', 'ADDPARAM', 'Value', pdfName) SRP_Com('', 'ADDPARAM', 'Value', wdFormatPDF$) SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') SRP_Com('', 'ADDPARAM', 'Omitted') oSaveAs = SRP_Com(oDocHandle2, 'ENDCALL', 'SAVEAS2')
  • Hi Kevin

    Tried that, got the same error 80020005. I checked the number of parameters and it is correct.

    This problem only arose in OI10 - with OI9 it worked perfectly. So it must be a 64 bit issue.

    Regards
    Nick
  • This problem only arose in OI10 - with OI9 it worked perfectly. So it must be a 64 bit issue.

    In OI9, does it work if you only pass in the FileName and FileFormat arguments? Also, does it work in OI 9 with both SRP_COM and the native OLE functions?

    I've not tried to work with OLE automation and Word yet. I've done extensive work with Excel. It has a SaveAs method (not SaveAs2). These methods are similar in that they both have several optional arguments. I found that I'm able to leave out those optional arguments if they appear at the end, but if I need to skip any then I need to use the method that Kevin posted.
    SRP_Com(objWorkbook@, 'CALL', 'SaveAs', DocumentPath, xlWorkbookDefault$, DocumentPassword)
    What does that mean? Not sure other than SaveAs works for Excel in 32-bit and 64-bit. Therefore, I am a bit surprised that it isn't working for Word. I'm eager to get your answer to my 32-bit questions.

    P.S. I doubt that it matters, but SaveAs and SaveAs2 return nothing which is why my syntax is called as a routine rather than a function.
  • Definitely worked with OpenInsight OLE in OI9. I'm going to try and fire up the old OI9 system and check with SRP_COM. I compared timings of SAVEAS (to PDF) and PRINTOUT (to Broadgun pdfMachine - 3rd party printer driver that prints to PDF) and found that actually Broadgun was faster at creating a PDF than WORD SAVEAS was. So stayed with Broadgun.

    The reason I'm trying this now is because we want to move away from 3rd party software (like Broadgun).

    Never had a problem passing parameters - the ones I needed were always first in line so never had a missing one to deal with.
  • Don, apologies, I can confirm that in OI9.4.4 SAVEAS to PDF worked using the native OLE functions, but SRP_COM fails with 80020005. I applied the latest SRP utilities as the version I was using was about 10 years old. I also tried SRP_COM with and without Kevin's earlier suggestion to initialise all parameters.
  • Looking at similar issues with Word automation in other languages, it appears that Word will not accept omitting variables. Instead, you must specify that each one is a missing reference. I'll investigate further on my end, but here are two things to try.

    First, replace "Omitted" with "Object" in the above ADDPARAM lines and see if that makes a difference. By using "Object" and not supplying a third parameter, it should pass a NULL reference to Word.

    If that doesn't work, it would be helpful to have some code to replicate. I can slap something together, but it'll take me some time. If, however, you have a stand-alone routine I can run, I'll be able to isolate the issue sooner.
  • Hi Kevin

    Here is some code cobbled together to illustrate the problem. Adjust the RUN VARIABLES to point to an existing WORD document, and choose whether to use native OI OLE or SRP_COM, and whether you want to just print the document or save as a PDF.

    You'll find the native OI works in OI9+ for both printing and saving as PDF.
    But SRP_COM fails on save as PDF in both OI9+ and OI10+ as well as fails to print if wdBackground$ is a parm.

    compile subroutine OLE_Word_Automation_test(err)

    /* Author NS
    Date December 2017
    Purpose To automate a mail merge using OLE
    */

    Declare Function OleCreateInstance, OleGetProperty, OleStatus, Msg, srp_com
    Declare Subroutine OlePutProperty

    $insert msg_equates

    * SET RUN VARIABLES ******************************************************************************************
    **************************************************************************************************************
    MergeDocument = 'I:\Development\IPS_DEV_94\Documents\mytestdocument.docx' ;* full path and filename of WORD document
    FileToSaveAs = 'I:\Development\IPS_DEV_94\Documents\mytestdocument.pdf' ;* full path and filename of PDF file to create

    printToPDF = 1 ;* set to 1 to SAVEAS PDF, set to 0 to just print to default printer

    *oleMethod = 'SRP' ;* use SRP OLE wrapper SRP_COM
    oleMethod = 'OI' ;* use OI OLE functions

    **************************************************************************************************************
    **************************************************************************************************************

    * set process vars
    oleError = ''

    * make sure the FileToSaveAs file does not exist
    if len(FileToSaveAs) and FileToSaveAs # MergeDocument then
    osDelete FileToSaveAs
    End

    DEBUG

    * create Word instance
    if oleMethod = 'OI' then
    oWordApp = OleCreateInstance("Word.Application")
    end else
    retVal = SRP_Com(oWordApp, 'CREATE', "Word.Application")
    end
    gosub CheckError

    * get next document handle
    if OleStatus else
    if oleMethod = 'OI' then
    oNextHandle = OleGetProperty(oWordApp, "DOCUMENTS")
    end else
    oNextHandle = SRP_Com(oWordApp, "GET", "DOCUMENTS")
    end
    gosub CheckError
    end

    * make Word visible but minimised
    if OLEStatus else
    wdVisible$ = 1
    if oleMethod = 'OI' then
    OlePutProperty(oWordApp, "VISIBLE", wdVisible$)
    end else
    Result = SRP_Com(oWordApp, "SET", "VISIBLE", wdVisible$)
    end

    gosub CheckError
    if OleStatus else
    wdMinimise$ = 2
    if oleMethod = 'OI' then
    OlePutProperty(oWordApp, "WINDOWSTATE", wdMinimise$)
    end else
    Result = SRP_Com(oWordApp, "SET", "WINDOWSTATE", wdMinimise$)
    end
    gosub CheckError
    end
    end

    * open the Word document
    if OleStatus else
    if oleMethod = 'OI' then
    oDocHandle = OleCallMethod(oNextHandle, "OPEN", MergeDocument)
    end else
    oDocHandle = SRP_Com(oNextHandle, "CALL", "OPEN", MergeDocument)
    end
    gosub CheckError
    end

    * print the document or save as PDF
    if OLEStatus else
    if PrintToPDF then
    * uses Word to SAVEAS PDF
    wdFormatPDF$ = 17

    *https://learn.microsoft.com/en-us/office/vba/api/word.saveas2
    if oleMethod = 'OI' then
    oSaveAs = OleCallMethod(oDocHandle, "SAVEAS2", FileToSaveAs, wdFormatPDF$)
    end Else
    srpVal = SRP_Com('', 'BEGINCALL')
    srpVal = SRP_Com('', 'ADDPARAM', 'Value', FileToSaveAs)
    srpVal = SRP_Com('', 'ADDPARAM', 'Value', wdFormatPDF$)
    For xx = 1 To 15
    srpVal = SRP_Com('', 'ADDPARAM', 'Object')
    Next xx
    oSaveAs = SRP_Com(oDocHandle, 'ENDCALL', 'SAVEAS2')
    *oSaveAs = SRP_Com(oDocHandle, "CALL", "SAVEAS2", pdfName, wdFormatPDF$)
    end
    end Else
    * prints the document to the selected device
    wdBackground$ = 0

    *https://learn.microsoft.com/en-us/office/vba/api/word.application.printout
    if oleMethod = 'OI' then
    oPrintOut = OleCallMethod(oWordApp, "PRINTOUT",wdBackground$)
    *oPrintOut = OleCallMethod(oDocHandle, "PRINTOUT",wdBackground$)
    end else
    oPrintOut = SRP_Com(oWordApp, "CALL", "PRINTOUT", wdBackground$)
    * seems to be a problem with wdBackground$ parm, so dropped it
    *oPrintOut = SRP_Com(oDocHandle, "CALL", "PRINTOUT")
    end
    * seems to be a problem with wdBackground$ parm, so dropped it
    end
    gosub CheckError
    end

    * close the Word document
    if OLEStatus else
    wdSaveChanges$ = 0
    if oleMethod = 'OI' then
    oCloseNew = OleCallMethod(oDocHandle, "CLOSE", wdSaveChanges$)
    end else
    oCloseNew = SRP_Com(oDocHandle, 'CALL', "CLOSE", wdSaveChanges$)
    end
    gosub CheckError
    end

    * always try to quit even with previous error so that Word isn't holding the document locked
    wdSaveChanges$ = 0 ;* -2

    * clear idispatch variables in the REVERSE order they were created
    if oleMethod = 'SRP' then
    retVal = SRP_Com(oCloseNew, 'RELEASE')
    retVal = SRP_Com(oPrintOut, 'RELEASE')
    retVal = SRP_Com(oSaveAs, 'RELEASE')
    retVal = SRP_Com(oDocHandle, 'RELEASE')
    retVal = SRP_Com(oNextHandle, 'RELEASE')
    end

    oCloseNew = ""
    oPrintOut = ""
    oSaveAs = ""
    oDocHandle = ""
    oNextHandle = ""

    * quit word application
    if oleMethod = 'OI' then
    Quit = OleCallMethod(oWordApp, "QUIT", wdSaveChanges$)
    end else
    Quit = SRP_Com(oWordApp, 'CALL', "QUIT", wdSaveChanges$)
    end

    * clear final idispatch variable
    if oleMethod = 'SRP' then
    retVal = SRP_Com(Quit, 'RELEASE')
    retVal = SRP_Com(oWordApp, 'RELEASE')
    end
    Quit = ""
    oWordApp = ""
    gosub CheckError

    Return
    *-------------------------------------------------------------------------------
    CheckError:

    * get the error
    OleStatus = ''
    if oleMethod = 'OI' then
    OleStatus = OleStatus()
    end else
    if SRP_Com('', 'ERROR') then
    OleStatus = SRP_Com('', 'ERROR')
    end
    end

    * see if the error is in the errors file
    if OleStatus then
    oleErrorDesc = ''
    wdVisible$ = -1
    if oleMethod = 'OI' then
    OlePutProperty(oWordApp, "VISIBLE", wdVisible$)
    end else
    Result = SRP_Com(oWordApp, "SET", "VISIBLE", wdVisible$)
    end

    msg_def = ""
    msg_def<3> = 'S'
    msg_def = "BO"
    msg_def = -2
    msg_def = 'OLE fatal error: ':OleStatus
    msgRetVal = MSG(@WINDOW,msg_def)
    oleError = OleStatus
    end

    Return
    *-------------------------------------------------------------------------------
  • edited February 8
    I really appreciate the sample code. It allowed me to dive right into the issue... and boy was it a twisty rabbit hole. The fix was simple, but figuring out the issue took me all morning.

    When using COM automation, all parameters are passed as VARIANTs. These huge structures cover all the known types and it's up to Word to correctly convert these variants into whatever it needs. Most COM servers will do a good job converting a huge variety of VARIANTs if possible. For example, I can give Excel a number as a string (variant type VT_BSTR) or any variety of number(VT_INT, VT_UI8, etc.) and Excel will be able to handle it. Word, however, picks a single variant type and sends our beloved Type Mismatch exception when it doesn't get precisely what it wants. As you can see here, there are lot of variant options.

    So, what was happening was that I was sending a variant of type VT_INT when you passed the file format type, but Word insists that it must be VT_I4. The difference is that VT_INT will be 32-bit on 32-bit Windows and 64-bit on 64-bit Windows whereas VT_I4 is always 32-bit. It took a LOT of google searches before I found this to be the issue. Microsoft does not document anywhere what VARIANT types it expects. If Microsoft is going to be picky, it should let users know. I had to discover the solution on an obscure reddit post.

    With that, I give you version 2.2.11.0 of the SRP Utilities. It will now convert to VT_I4 for numbers that are recognized to fit within a signed 32-bit integer, instead of using VT_INT. You may also go back to using the simpler CALL service rather than the more complication BEGINCALL...ENDCALL. In my test, the following worked fine:

    oSaveAs = SRP_Com(oDocHandle, "CALL", "SAVEAS2", FileToSaveAs, wdFormatPDF$)
  • Hi Kevin

    Really appreciate your help! The SAVEAS is working perfectly, however I still get the dreaded 80020005 when printing, using:

    wdBackground$ = 0
    oPrintOut = SRP_Com(oDocHandle, "CALL", "PRINTOUT", wdBackground$)

    If I remove the wdBackground$ parameter, the error goes away, but then WORD releases control back to the calling proc and WORD gets closed before the printing is finished, leaving a corrupted or partial document on the printer. I think background printing is usually set on WORD installs so I need to override it.

    I may have a workaround by using
    oBusy = SRP_Com(oWordApp, "GET", "BACKGROUNDPRINTINGSTATUS")

    But just thought I'd let you know anyway.

    Many thanks,
    Nick
Sign In or Register to comment.