Jefrey

Word UDF bug? Unable to write 256+ chars using DocFindReplace

8 posts in this topic

Hi, I'm having a trouble.

I'm writing a project for a company. I have an interface with many text inputs. The user will fill up that inputs, then my application will create a log. This log must be in word format (otherwise I'd write a simple HTML file and convert it using "wkhtmltopdf" command line tool) and the user must put a large amount of data.

Also, I have to use _Word_DocFindReplace() function because the final log that the user will see must follow a model that the company has gave to me.

But it seems that this function can't handle more than 255 characters. Look at this example:

I made a file called "test.docx" using Word in the script dir. Its content is just:

%TEXT%

Nothing more. Now I have this code:

#include <Word.au3>

$word = _Word_Create(True, True)
$oword = _Word_DocOpen($word, 'test.docx')

; 255 times A
$texto = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'

_Word_DocFindReplace($oword, "%TEXT%", $texto)

In this code, everything works fine. In the file opened, I see that the %TEXT% has got replaced by 255 As.

But if I add just one A...

#include <Word.au3>

$word = _Word_Create(True, True)
$oword = _Word_DocOpen($word, 'test.docx')

; 256 times A
$texto = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'

_Word_DocFindReplace($oword, "%TEXT%", $texto)

...nothing gots replaced. In the file opened, I see just %TEXT%.

I can't predict how many lines the user will write, so I can't put many %LINE1%, %LINE2% etc. Also, I can't check how many lines the user wrote in the instant (then write the %LINE1%, %LINE2%...) because the user must be able to edit the template in Word manually.

I'm using a 32-bit machine, by the way.

Is that a security measure, from the Word object or UDF, against buffer overflow or something? Or a Windows standard? Or some bug?
Or that's just with my computer?

Thanks!


My stuff

Spoiler

My UDFs  _AuThread multithreading emulation for AutoIt · _ExtInputBox an inputbox with multiple inputs and more features · forceUTF8 fix strings encoding without knowing its original charset · JSONgen JSON generator · _TCPServer UDF multi-client and multi-task (run on background) event-based TCP server easy to do · _TCPClient_UDF multi-server and multi-task (runs on background) event-based TCP client easy to do · ParseURL and ParseStr functions ported from PHP · _CmdLine UDF easily parse command line parameters, keys or flags · AutoPHP Create documents (bills, incomes) from HTML by sending variables/arrays from AutoIt to PHP · (Un)Serialize Convert arrays and data into a storable string (PHP compatible) · RTTL Plays and exports to MP3 Nokia-format monophonic ringtones (for very old cellphones) · I18n library Simple and easy to use localization library · Scripting.Dictionary OOP and OOP-like approach · Buffer/stack limit arrays to N items by removing the last one once the limit is reached · NGBioAPI UDF to work with Nitgen fingerprint readers · Serial/Licensing system require license key based on unique machine ID from your users · HTTP a simple WinHTTP library that allows GET, POST and file uploads · Thread true AutoIt threads (under-dev) · RC4 RC4 encryption compatible with PHP and JS Classes _WKHtmlToX uses wkhtmlto* to convert HTML files and webpages into PDF or images (jpg, bmp, gif, png...) Snippets _Word_DocFindReplaceByLongText replace strings using Word UDF with strings longer than 255 characters (MSWord limit) rangeparser parser for printing-like pages interval (e.g.: "1,2,3-5") EnvParser parse strings/paths with environment variables and get full path Random stuff Super Mario beep sound your ears will hurt

 

Share this post


Link to post
Share on other sites



What's the return value and @error of _Word_DocFindReplace?


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

@error = 3

@extended = 0


My stuff

Spoiler

My UDFs  _AuThread multithreading emulation for AutoIt · _ExtInputBox an inputbox with multiple inputs and more features · forceUTF8 fix strings encoding without knowing its original charset · JSONgen JSON generator · _TCPServer UDF multi-client and multi-task (run on background) event-based TCP server easy to do · _TCPClient_UDF multi-server and multi-task (runs on background) event-based TCP client easy to do · ParseURL and ParseStr functions ported from PHP · _CmdLine UDF easily parse command line parameters, keys or flags · AutoPHP Create documents (bills, incomes) from HTML by sending variables/arrays from AutoIt to PHP · (Un)Serialize Convert arrays and data into a storable string (PHP compatible) · RTTL Plays and exports to MP3 Nokia-format monophonic ringtones (for very old cellphones) · I18n library Simple and easy to use localization library · Scripting.Dictionary OOP and OOP-like approach · Buffer/stack limit arrays to N items by removing the last one once the limit is reached · NGBioAPI UDF to work with Nitgen fingerprint readers · Serial/Licensing system require license key based on unique machine ID from your users · HTTP a simple WinHTTP library that allows GET, POST and file uploads · Thread true AutoIt threads (under-dev) · RC4 RC4 encryption compatible with PHP and JS Classes _WKHtmlToX uses wkhtmlto* to convert HTML files and webpages into PDF or images (jpg, bmp, gif, png...) Snippets _Word_DocFindReplaceByLongText replace strings using Word UDF with strings longer than 255 characters (MSWord limit) rangeparser parser for printing-like pages interval (e.g.: "1,2,3-5") EnvParser parse strings/paths with environment variables and get full path Random stuff Super Mario beep sound your ears will hurt

 

Share this post


Link to post
Share on other sites

When searching Google you'll find entries describing a 256 character limit of Word. Seems there is no easy workaround.


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

#5 ·  Posted (edited)

Thanks for pointing me out that limitation! Following this logic, I wrote this function (quite workaround, maybe?):

Func _Word_DocFindReplaceByLongText(ByRef $oDoc, $sFindText = "", $sReplaceWith = "", $iReplace = $WdReplaceAll, $vSearchRange = 0, $bMatchCase = False, $bMatchWholeWord = False, $bMatchWildcards = False, $bMatchSoundsLike = False, $bMatchAllWordsForm = False, $bForward = True, $iWrap = $WdFindContinue, $bFormat = False)
    ; We need at least 1 char to put part of $sReplaceWith
    ; Therefore, $sFindText can't have more than 255 chars (the Word limit)
    If StringLen($sFindText) > 254 Then
        Return SetError(1, 0, False)
    EndIf

    ; This is our limit of chars per part of $sReplaceWith
    $iLimit = 255-StringLen($sFindText)

    If StringLen($sReplaceWith) < 255 Then
        ; If $sReplaceWith is under the limit, we don't need to do anything
        ; Just call the standard function
        _Word_DocFindReplace($oDoc, $sFindText, $sReplaceWith, $iReplace, $vSearchRange, $bMatchCase, $bMatchWholeWord, $bMatchWildcards, $bMatchSoundsLike, $bMatchAllWordsForm, $bForward, $iWrap, $bFormat)
        If @error Then
            Return SetError(@error, @extended, False)
        Else
            Return True
        EndIf
    Else
        ; First we split the string
        $aParts = StringRegExp($sReplaceWith, "(?s).{1," & $iLimit & "}", 3)

        ; Now we have a 0-based array.
        ; We go replacing it, but keeping $sFindText at its end
        $j = UBound($aParts)-1
        For $i = 0 to $j
            $sPart = $aParts[$i]

            ; if it's not the last part, append $sFindText to the end
            If $i < $j Then $sPart &= $sFindText
            _Word_DocFindReplace($oDoc, $sFindText, $sPart, $iReplace, $vSearchRange, $bMatchCase, $bMatchWholeWord, $bMatchWildcards, $bMatchSoundsLike, $bMatchAllWordsForm, $bForward, $iWrap, $bFormat)
            If @error Then
                Return SetError(@error, @extended, False)
            EndIf
        Next
    EndIf
EndFunc

Now even this works fine:

#include <Word.au3>
#include <String.au3>

$word = _Word_Create(True, True)
$oword = _Word_DocOpen($word, 'test.docx')

$replacewith = _StringRepeat("A", 9999)

_Word_DocFindReplaceByLongText($oword, "%TEXT%", $replacewith)
Edited by Jefrey

My stuff

Spoiler

My UDFs  _AuThread multithreading emulation for AutoIt · _ExtInputBox an inputbox with multiple inputs and more features · forceUTF8 fix strings encoding without knowing its original charset · JSONgen JSON generator · _TCPServer UDF multi-client and multi-task (run on background) event-based TCP server easy to do · _TCPClient_UDF multi-server and multi-task (runs on background) event-based TCP client easy to do · ParseURL and ParseStr functions ported from PHP · _CmdLine UDF easily parse command line parameters, keys or flags · AutoPHP Create documents (bills, incomes) from HTML by sending variables/arrays from AutoIt to PHP · (Un)Serialize Convert arrays and data into a storable string (PHP compatible) · RTTL Plays and exports to MP3 Nokia-format monophonic ringtones (for very old cellphones) · I18n library Simple and easy to use localization library · Scripting.Dictionary OOP and OOP-like approach · Buffer/stack limit arrays to N items by removing the last one once the limit is reached · NGBioAPI UDF to work with Nitgen fingerprint readers · Serial/Licensing system require license key based on unique machine ID from your users · HTTP a simple WinHTTP library that allows GET, POST and file uploads · Thread true AutoIt threads (under-dev) · RC4 RC4 encryption compatible with PHP and JS Classes _WKHtmlToX uses wkhtmlto* to convert HTML files and webpages into PDF or images (jpg, bmp, gif, png...) Snippets _Word_DocFindReplaceByLongText replace strings using Word UDF with strings longer than 255 characters (MSWord limit) rangeparser parser for printing-like pages interval (e.g.: "1,2,3-5") EnvParser parse strings/paths with environment variables and get full path Random stuff Super Mario beep sound your ears will hurt

 

Share this post


Link to post
Share on other sites

Thanks a lot for your reply!

You are the first one who reached this limit.

At the moment the Word UDF is only a simple wrapper for some methods of the Word object model. This way you see all the limitations of this object model.

If this problem happens more often we might think about including your work around into the UDF.

But by posting your code every user hitting this limitation can find the solution!


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

#7 ·  Posted

Guys,

First, I know this post is now 2 years old.  I also think no further dev has been done on AutoIT for quite some time (not been following beta's though), of which I don't understand, because I LOVE this application!  Water, you have been the inspiration for many of my applications as I don't know who this is  "Bob Anthony, rewritten by water", but I know I've used this one, the excel one, and Dales IE one ALOT!  so thanks all you guys.  and in the almost 6 years now of writing apps for myself and my team at work, I just have been having a ball!  Most of all, the help this forum gives has been great!  (OK, I'll stop praising now...).

 

But yes, I have finally hit that limitation, so I'll have to try to work in this "work around" now.  it totally caught me off guard.  I have a template where I "Moosh" many documents into 1, and in the header, I put a title section of who contributed (authored) those text blurbs.  typically it is only 1 or 2, but the other day I saw 10 different folks, which meant the "header" text got too large, and failed (took a lot of time to figure out why after running it through 100 or so documents).  I saw the error 3, but that's all, it didn't say exactly why.  but searching here and finding this now, is excellent, as I'll be able to work this into my code (I hope). 

Thanks Jefrey for the work around.  My question for water is, though, which would be faster?  using his workaround, or adding in a different type of workaround, using the search range function, changing the range based on the part of text you copy in (255 at a time), and keep increasing the range start/end until you've copied in all the text?

for example:

$vRange = $oDoc.Parent.Selection.Range
$vRange.paste()
$vRange.MoveStart($iStartUnit, $iStartCount)
$vRange.MoveEnd($iEndUnit, $iEndCount)
$vRange.paste()

This is by no means complete code, I'm just referencing other sections of your "_Word_DocRangeSet" Function, to outline maybe a faster way to write out the text (by moving the range selected?)

Thanks!

Share this post


Link to post
Share on other sites

#8 ·  Posted

I think your approach would be a bit faster as calling _Word_DocFindReplace multiple times has a bit of overhead.


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