----------------------------------------------------------
                           [BUG/PRB.] VFP 9.0 FIX - REPORT FOOTER
                                 January 2024
                 ----------------------------------------------------------
                                    CCB



1. BUG:

     There is a report for test:

     Paper: A4 (21.0cm x 29.7cm)
     Print area: Whole page
     Page Header: Height = 5.0cm
     Detail: Height = 2.0cm
     Page Footer: Height = 4.7cm or 4.65cm

     The report prints 10 records per page: 29.7cm = 5.0cm + 2.0cm x 10 + 4.7cm

     Please refer to the picture testreport.jpg:

     In vfp8, the report is correct for all printers.

     Please refer to the picture testreport8.jpg:

     But in vfp9, there are some blank spaces between the detail and the page footer.

     Please refer to the picture testreport9.jpg:


2. CAUSE:

     We can calculate the top non-printable area for different printer:

     GetDeviceCaps(hdc,PHYSICALOFFSETY) / GetDeviceCaps(hdc,LOGPIXELSY) x 2.54

     For Epson LQ-1600K, the value is 0.846667cm.
     For HP LaserJet 1020, the value is 0.397933cm.
     For Adobe PDF, the value is 0cm.

     This value is equal to the height of the blank spaces.

     The BUG is the top non-printable area has been added to the page footer.


3. RESOLUTION:

     We can write some code to fix the BUG.

     1, Please refer to the file vfp9fix.h:

     //+--------------------------------------------------------------------------
     //
     //    File:        pro_ext.h
     //
     //    Copyright:    (c) 1999, Microsoft Corporation.
     //                All Rights Reserved.
     //                Information Contained Herein is Proprietary
     //                and Confidential.
     //
     //    Contents:    API Header for the Library Construction Kit
     //
     //    Notes: 
     //
     //---------------------------------------------------------------------------
     #ifndef PRO_EXT_INCLUDED
     #define PRO_EXT_INCLUDED

     #if defined(_MSC_VER)
     #pragma pack(push, 1)                 // Assume byte structure packing
     #endif

     #ifdef __cplusplus
     extern "C" {                        // Assume C declarations for C++
     #endif

     // Fastcall calling convention
     #define FASTCALL _fastcall

     // FPFI is a 32 bit pointer to a function returning an int
     typedef long (*FPFI)();

     // The FoxInfo structure contains the descriptions of the functions
     // contained in the library.
     typedef struct {
         char *    funcName;        /* Function name (all caps)                */
         FPFI        function;       /* Actual function address              */
         short        parmCount;        /* # parameters specified or a flag value */
         char *    parmTypes;        /* Parameter list description            */
     } FoxInfo;

     typedef struct _FoxTable {
         struct _FoxTable *nextLibrary;    /* Linked list of libraries        */
         short infoCount;            /* # of functions in this library        */
         FoxInfo *infoPtr;        /* Function list                        */
     } FoxTable;

     // An expression's value
     typedef struct {
         char                ev_type;
         char                ev_padding;
         short                ev_width;
         unsigned             ev_length;
         long                ev_long;
         double                ev_real;
         long                ev_currency;
         long                ev_currency2;
         unsigned            ev_handle;
         unsigned long        ev_object;
     } Value;

     // A reference to a database or memory variable
     typedef struct {
         char        l_type;
         short        l_where,        /* Database number or -1 for memory        */
                     l_NTI,            /* Variable name table offset            */
                     l_offset,        /* Index into database                    */
                     l_subs,            /* # subscripts specified 0 <= x <= 2    */
                     l_sub1, l_sub2; /* subscript integral values            */
     } Locator;

     typedef union {
         Value        val;
         Locator        loc;            /* An 'R' in l_type means the Locator    */
                                     /* part of this union is in use.        */
     } FoxParameter;

     // A paramter list to a library function.
     typedef struct {
         short         pCount;            /* Number of Parameters PASSED.            */
         FoxParameter    p[1];        /* pCount Parameters.                    */
     } ParamBlk;

     int FASTCALL _Execute(char *stmt);
     int FASTCALL _Evaluate(Value *val, char *expr);
     void FASTCALL _Error(int code);
     void FASTCALL _RetVal(Value *val);
     int FASTCALL _Store(Locator *loc, Value *val);
     int FASTCALL _Load(Locator *loc, Value *val);
     int FASTCALL _FindVar(int nti, int where, Locator *loc);
     int FASTCALL _NameTableIndex(char *name);

     #ifdef __cplusplus
     }                       // End of extern "C" {
     #endif

     #if defined(_MSC_VER)
     #pragma pack(pop)          // Restore structure packing
     #endif

     #endif                  // PRO_EXT_INCLUDED


     2, Please refer to the file vfp9fix.c:

     #include "vfp9fix.h"

     int __stdcall VirtualProtect(void *lpAddress, int dwSize, int flNewProtect, int *lpflOldProtect);

     void VFP9FixReportFooter()
     {
         Value hmodule0retvalue;
         unsigned int hmodule0;
         unsigned int i;
         unsigned char *p1;
         unsigned char *p2;
         unsigned int OldProtect;
         _Execute("DECLARE integer GetModuleHandle IN win32api string lpfilename");
         _Evaluate(&hmodule0retvalue,"GetModuleHandle(_vfp.fullname)");
         hmodule0=hmodule0retvalue.ev_long;
         for (i=0x080000;i<0x100000;i++)
         {
             p1=hmodule0+i;
             if (*(p1+0x09)==0x8B &&
                 *(p1+0x0A)==0x50 &&
                 *(p1+0x0B)==0x0C &&
                 *(p1+0x0C)==0x2B &&
                 *(p1+0x0D)==0x56 &&
                 *(p1+0x0E)==0x68 &&
                 *(p1+0x0F)==0x03 &&
                 *(p1+0x10)==0x56 &&
                 *(p1+0x11)==0x58)
             {

                 // fix vfp9.exe, vfp9r.dll
                 // 00498A70    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
                 // 00498A73    8078 15 00      CMP BYTE PTR DS:[EAX+15],0
                 // 00498A77    75 1A           JNZ SHORT VFP9.00498A93
                 // 00498A79    8B50 0C         MOV EDX,DWORD PTR DS:[EAX+C]
                 // 00498A7C    2B56 68         SUB EDX,DWORD PTR DS:[ESI+68]
                 // 00498A7F    0356 58         ADD EDX,DWORD PTR DS:[ESI+58]
                 // 00498A82    E8 58BBFFFF     CALL VFP9.004945DF
                 // 00498A87    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
                 // 00498A8A    8B4E 68         MOV ECX,DWORD PTR DS:[ESI+68]
                 // 00498A8D    2B48 0C         SUB ECX,DWORD PTR DS:[EAX+C]
                 // 00498A90    894E 58         MOV DWORD PTR DS:[ESI+58],ECX

                 // fix to:
                 // 00498A70    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
                 // 00498A73    50              PUSH EAX
                 // 00498A74    BF 14010000     MOV EDI,114
                 // 00498A79    8B50 0C         MOV EDX,DWORD PTR DS:[EAX+C]
                 // 00498A7C    2B56 68         SUB EDX,DWORD PTR DS:[ESI+68]
                 // 00498A7F    0356 58         ADD EDX,DWORD PTR DS:[ESI+58]
                 // 00498A82    E8 58BBFFFF     CALL VFP9.004945DF
                 // 00498A87    33FF            XOR EDI,EDI
                 // 00498A89    58              POP EAX
                 // 00498A8A    8B4E 68         MOV ECX,DWORD PTR DS:[ESI+68]
                 // 00498A8D    2B48 0C         SUB ECX,DWORD PTR DS:[EAX+C]
                 // 00498A90    894E 58         MOV DWORD PTR DS:[ESI+58],ECX

                 for (i=0x080000;i<0x100000;i++)
                 {
                     p2=hmodule0+i;
                     if (*(p2+0x0E)==0x05 &&
                         *(p2+0x0F)==0x14 &&
                         *(p2+0x10)==0x01 &&
                         *(p2+0x11)==0x00 &&
                         *(p2+0x12)==0x00 &&
                         *(p2+0x13)==0x29 &&
                         *(p2+0x14)==0x50 &&
                         *(p2+0x15)==0xF8 &&
                         *(p2+0x16)==0x29 &&
                         *(p2+0x17)==0x10)
                     {

                         // fix vfp9.exe, vfp9r.dll
                         // 004945DF    8B48 20         MOV ECX,DWORD PTR DS:[EAX+20]
                         // 004945E2    85C9            TEST ECX,ECX
                         // 004945E4    74 19           JE SHORT VFP9.004945FF
                         // 004945E6    8B40 24         MOV EAX,DWORD PTR DS:[EAX+24]
                         // 004945E9    8B00            MOV EAX,DWORD PTR DS:[EAX]
                         // 004945EB    7E 12           JLE SHORT VFP9.004945FF
                         // 004945ED    05 14010000     ADD EAX,114
                         // 004945F2    2950 F8         SUB DWORD PTR DS:[EAX-8],EDX
                         // 004945F5    2910            SUB DWORD PTR DS:[EAX],EDX
                         // 004945F7    05 4C010000     ADD EAX,14C
                         // 004945FC    49              DEC ECX
                         // 004945FD    75 F3           JNZ SHORT VFP9.004945F2
                         // 004945FF    C3              RETN

                         // fix to:
                         // 004945DF    807C3E CC 00    CMP BYTE PTR DS:[ESI+EDI-34],0
                         // 004945E4    74 03           JE SHORT VFP9.004945E9
                         // 004945E6    03143E          ADD EDX,DWORD PTR DS:[ESI+EDI]
                         // 004945E9    8B48 20         MOV ECX,DWORD PTR DS:[EAX+20]
                         // 004945EC    E3 11           JECXZ SHORT VFP9.004945FF
                         // 004945EE    8B40 24         MOV EAX,DWORD PTR DS:[EAX+24]
                         // 004945F1    8B00            MOV EAX,DWORD PTR DS:[EAX]
                         // 004945F3    03C7            ADD EAX,EDI
                         // 004945F5    2950 F8         SUB DWORD PTR DS:[EAX-8],EDX
                         // 004945F8    2910            SUB DWORD PTR DS:[EAX],EDX
                         // 004945FA    83C0 38         ADD EAX,38
                         // 004945FD    E2 F4           LOOPD SHORT VFP9.004945F3
                         // 004945FF    C3              RETN

                         // _Execute("_SCREEN.VISIBLE=.T.");
                         // _Execute("WAIT WIND 'VFP9FixReportFooter OK.'");

                         OldProtect=0x20; // PAGE_EXECUTE_READ
                         VirtualProtect(p1,0x20,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
                         *(p1+0x03)=0x50;
                         *(p1+0x04)=0xBF;
                         *(p1+0x05)=0x14;
                         *(p1+0x06)=0x01;
                         *(p1+0x07)=0x00;
                         *(p1+0x08)=0x00;
                         *(p1+0x17)=0x33;
                         *(p1+0x18)=0xFF;
                         *(p1+0x19)=0x58;
                         VirtualProtect(p1,0x20,OldProtect,&OldProtect);

                         OldProtect=0x20; // PAGE_EXECUTE_READ
                         VirtualProtect(p2,0x20,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
                         *(p2+0x00)=0x80;
                         *(p2+0x01)=0x7C;
                         *(p2+0x02)=0x3E;
                         *(p2+0x03)=0xCC;
                         *(p2+0x04)=0x00;
                         *(p2+0x05)=0x74;
                         *(p2+0x06)=0x03;
                         *(p2+0x07)=0x03;
                         *(p2+0x08)=0x14;
                         *(p2+0x09)=0x3E;
                         *(p2+0x0A)=0x8B;
                         *(p2+0x0B)=0x48;
                         *(p2+0x0C)=0x20;
                         *(p2+0x0D)=0xE3;
                         *(p2+0x0E)=0x11;
                         *(p2+0x0F)=0x8B;
                         *(p2+0x10)=0x40;
                         *(p2+0x11)=0x24;
                         *(p2+0x12)=0x8B;
                         *(p2+0x13)=0x00;
                         *(p2+0x14)=0x03;
                         *(p2+0x15)=0xC7;
                         *(p2+0x16)=0x29;
                         *(p2+0x17)=0x50;
                         *(p2+0x18)=0xF8;
                         *(p2+0x19)=0x29;
                         *(p2+0x1A)=0x10;
                         *(p2+0x1B)=0x83;
                         *(p2+0x1C)=0xC0;
                         *(p2+0x1D)=0x38;
                         *(p2+0x1E)=0xE2;
                         *(p2+0x1F)=0xF4;
                         VirtualProtect(p2,0x20,OldProtect,&OldProtect);
                         break;
                     }
                 }
                 break;
             }
         }
     }

     FoxInfo myFoxInfo[]={
     {"VFP9FixReportFooter",(FPFI)VFP9FixReportFooter,0,""},
     };

     FoxTable _FoxTable={
     (FoxTable *)0,sizeof(myFoxInfo)/sizeof(FoxInfo),myFoxInfo
     };


     3, Please refer to the file make.bat:

     @echo off

     rem ;-----------------------------------------------;
     rem ;       VFP9fix Maker Program                   ;
     rem ;           Make.bat                            ;
     rem ;       (C)Mr. Chen, 2009.11                    ;
     rem ;       E-mail: ccb2000@163.com                 ;
     rem ;-----------------------------------------------;

     rem NMAKE /f "vfp9fix.mak" CFG="vfp9fix - Win32 Release"

     if exist .\vfp9fix.dll del .\vfp9fix.dll
     if exist .\vfp9fix.obj del .\vfp9fix.obj
     if exist .\vfp9fix.lib del .\vfp9fix.lib
     if exist .\vfp9fix.exp del .\vfp9fix.exp
     if exist .\vfp9fix.pch del .\vfp9fix.pch

     cl /nologo /Gr /MD /w /W0 /Ox /Ob1 /Os /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Zm1000 /c vfp9fix.c
     if not exist .\vfp9fix.obj pause

     link kernel32.lib user32.lib uuid.lib winapims.lib /nologo /subsystem:windows /dll /incremental:no
     /machine:I386 /out:".\vfp9fix.dll" /implib:".\vfp9fix.lib" ".\vfp9fix.obj"


     Then run make.bat, we can build a VFP API Library file: vfp9fix.dll.


     4, Please refer to the file f_vfp9fixreportfooterwithdll.prg:

     *PROC f_vfp9fixreportfooterwithdll

     * VFP 9.0 FIX - REPORT FOOTER with vfp9fix.dll
     * ccb2000@163.com, 2010.1

     PRIVATE m.q_vfp9fixreportfooter
     m.q_vfp9fixreportfooter=.T.

     IF ROUND(VAL(CHRTRAN(UPPE(VERSION()),"MICROSOFTVISUALFOXPRO","")),2)=9.0

        PRIVATE m.q_errnum,m.q_erroron
        m.q_errnum=0
        m.q_erroron=ON("ERROR")
        ON ERROR m.q_errnum=ERROR()
        SET LIBRARY TO ("vfp9fix.dll") ADDITIVE
        ON ERROR &q_erroron

        IF .F.
           PUBLIC vfp9fixreportfooter(1)
        ENDI

        IF m.q_errnum#0
           m.q_vfp9fixreportfooter=.F.
           RETU m.q_vfp9fixreportfooter
        ENDI

        PRIVATE m.q_errnum,m.q_erroron
        m.q_errnum=0
        m.q_erroron=ON("ERROR")
        ON ERROR m.q_errnum=ERROR()
        =vfp9fixreportfooter()
        ON ERROR &q_erroron

        IF m.q_errnum#0
           m.q_vfp9fixreportfooter=.F.
           RETU m.q_vfp9fixreportfooter
        ENDI

        PRIVATE m.q_errnum,m.q_erroron
        m.q_errnum=0
        m.q_erroron=ON("ERROR")
        ON ERROR m.q_errnum=ERROR()
        RELEASE LIBRARY ("vfp9fix.dll")
        ON ERROR &q_erroron

        IF m.q_errnum#0
           m.q_vfp9fixreportfooter=.F.
           RETU m.q_vfp9fixreportfooter
        ENDI

        m.q_vfp9fixreportfooter=.T.
        RETU m.q_vfp9fixreportfooter

     ENDI

     m.q_vfp9fixreportfooter=.T.
     RETU m.q_vfp9fixreportfooter

     * END OF PROC F_VFP9FIXREPORTFOOTERWITHDLL.


     5, Please refer to the file f_vfp9fixreportfooter.prg:

     *PROC f_vfp9fixreportfooter

     * VFP 9.0 FIX - REPORT FOOTER
     * ccb2000@163.com, 2010.12

     PRIVATE m.q_vfp9fixreportfooter
     m.q_vfp9fixreportfooter=.T.

     IF !ROUND(VAL(CHRTRAN(UPPE(VERSION()),"MICROSOFTVISUALFOXPRO","")),2)=9.0
        m.q_vfp9fixreportfooter=.T.
        RETU m.q_vfp9fixreportfooter
     ENDI

     DECLARE INTEGER "GetModuleHandle" IN win32api ;
        STRING lpfilename
     DECLARE INTEGER "GetCurrentProcess" IN win32api
     DECLARE INTEGER "ReadProcessMemory" IN win32api ;
        LONG    hprocess,;
        INTEGER lpbaseaddress,;
        STRING @lpbuffer,;
        INTEGER nsize,;
        INTEGER lpnumberofbytesread
     DECLARE INTEGER "WriteProcessMemory" IN win32api ;
        LONG    hprocess,;
        INTEGER lpbaseaddress,;
        STRING lpbuffer,;
        INTEGER nsize,;
        INTEGER lpnumberofbyteswritten
     DECLARE INTEGER "VirtualProtect" IN win32api ;
        INTEGER lpaddress,;
        INTEGER dwsize,;
        INTEGER flnewprotect,;
        INTEGER @lpfloldprotect

     IF .F.
        PUBLIC getmodulehandle(1)
        PUBLIC getcurrentprocess(1)
        PUBLIC readprocessmemory(1)
        PUBLIC writeprocessmemory(1)
        PUBLIC virtualprotect(1)
     ENDIF

     PRIVATE m.q_hmodule0
     m.q_hmodule0=0
     m.q_hmodule0=getmodulehandle(_VFP.FULLNAME)
     IF !m.q_hmodule0>0
        m.q_vfp9fixreportfooter=.F.
        RETU m.q_vfp9fixreportfooter
     ENDIF

     
     * for (i=0x080000;i<0x100000;i++)
     * {
     *     p1=hmodule0+i;
     *     if (*(p1+0x09)==0x8B &&
     *         *(p1+0x0A)==0x50 &&
     *         *(p1+0x0B)==0x0C &&
     *         *(p1+0x0C)==0x2B &&
     *         *(p1+0x0D)==0x56 &&
     *         *(p1+0x0E)==0x68 &&
     *         *(p1+0x0F)==0x03 &&
     *         *(p1+0x10)==0x56 &&
     *         *(p1+0x11)==0x58)
     *     {
     *
     *         // fix vfp9.exe, vfp9r.dll
     *         // 00498A70    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
     *         // 00498A73    8078 15 00      CMP BYTE PTR DS:[EAX+15],0
     *         // 00498A77    75 1A           JNZ SHORT VFP9.00498A93
     *         // 00498A79    8B50 0C         MOV EDX,DWORD PTR DS:[EAX+C]
     *         // 00498A7C    2B56 68         SUB EDX,DWORD PTR DS:[ESI+68]
     *         // 00498A7F    0356 58         ADD EDX,DWORD PTR DS:[ESI+58]
     *         // 00498A82    E8 58BBFFFF     CALL VFP9.004945DF
     *         // 00498A87    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
     *         // 00498A8A    8B4E 68         MOV ECX,DWORD PTR DS:[ESI+68]
     *         // 00498A8D    2B48 0C         SUB ECX,DWORD PTR DS:[EAX+C]
     *         // 00498A90    894E 58         MOV DWORD PTR DS:[ESI+58],ECX
     *
     *         // fix to:
     *         // 00498A70    8B46 10         MOV EAX,DWORD PTR DS:[ESI+10]
     *         // 00498A73    50              PUSH EAX
     *         // 00498A74    BF 14010000     MOV EDI,114
     *         // 00498A79    8B50 0C         MOV EDX,DWORD PTR DS:[EAX+C]
     *         // 00498A7C    2B56 68         SUB EDX,DWORD PTR DS:[ESI+68]
     *         // 00498A7F    0356 58         ADD EDX,DWORD PTR DS:[ESI+58]
     *         // 00498A82    E8 58BBFFFF     CALL VFP9.004945DF
     *         // 00498A87    33FF            XOR EDI,EDI
     *         // 00498A89    58              POP EAX
     *         // 00498A8A    8B4E 68         MOV ECX,DWORD PTR DS:[ESI+68]
     *         // 00498A8D    2B48 0C         SUB ECX,DWORD PTR DS:[EAX+C]
     *         // 00498A90    894E 58         MOV DWORD PTR DS:[ESI+58],ECX

     PRIVATE m.q_str1
     m.q_str1=REPL(CHR(0),0x100000-0x080000)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x080000,@m.q_str1,LEN(m.q_str1),0)

     PRIVATE m.q_p1_nn
     m.q_p1_nn=1

     DO WHILE .T.

        PRIVATE m.q_p1
        m.q_p1=AT(CHR(0x8b)+;
           CHR(0x50)+;
           CHR(0x0c)+;
           CHR(0x2b)+;
           CHR(0x56)+;
           CHR(0x68)+;
           CHR(0x03)+;
           CHR(0x56)+;
           CHR(0x58),m.q_str1,m.q_p1_nn)
        IF !m.q_p1>0
           m.q_vfp9fixreportfooter=.F.
           RETU m.q_vfp9fixreportfooter
        ENDIF
        m.q_p1=m.q_p1-0x09

        IF !(SUBS(m.q_str1,m.q_p1+0x09,1)==CHR(0x8b).AND.;
              SUBS(m.q_str1,m.q_p1+0x0a,1)==CHR(0x50).AND.;
              SUBS(m.q_str1,m.q_p1+0x0b,1)==CHR(0x0c).AND.;
              SUBS(m.q_str1,m.q_p1+0x0c,1)==CHR(0x2b).AND.;
              SUBS(m.q_str1,m.q_p1+0x0d,1)==CHR(0x56).AND.;
              SUBS(m.q_str1,m.q_p1+0x0e,1)==CHR(0x68).AND.;
              SUBS(m.q_str1,m.q_p1+0x0f,1)==CHR(0x03).AND.;
              SUBS(m.q_str1,m.q_p1+0x10,1)==CHR(0x56).AND.;
              SUBS(m.q_str1,m.q_p1+0x11,1)==CHR(0x58))
           m.q_p1_nn=m.q_p1_nn+1
           LOOP
        ENDIF

        EXIT

     ENDDO

     
     * for (i=0x080000;i<0x100000;i++)
     * {
     *     p2=hmodule0+i;
     *     if (*(p2+0x0E)==0x05 &&
     *         *(p2+0x0F)==0x14 &&
     *         *(p2+0x10)==0x01 &&
     *         *(p2+0x11)==0x00 &&
     *         *(p2+0x12)==0x00 &&
     *         *(p2+0x13)==0x29 &&
     *         *(p2+0x14)==0x50 &&
     *         *(p2+0x15)==0xF8 &&
     *         *(p2+0x16)==0x29 &&
     *         *(p2+0x17)==0x10)
     *     {
     *
     *         // fix vfp9.exe, vfp9r.dll
     *         // 004945DF    8B48 20         MOV ECX,DWORD PTR DS:[EAX+20]
     *         // 004945E2    85C9            TEST ECX,ECX
     *         // 004945E4    74 19           JE SHORT VFP9.004945FF
     *         // 004945E6    8B40 24         MOV EAX,DWORD PTR DS:[EAX+24]
     *         // 004945E9    8B00            MOV EAX,DWORD PTR DS:[EAX]
     *         // 004945EB    7E 12           JLE SHORT VFP9.004945FF
     *         // 004945ED    05 14010000     ADD EAX,114
     *         // 004945F2    2950 F8         SUB DWORD PTR DS:[EAX-8],EDX
     *         // 004945F5    2910            SUB DWORD PTR DS:[EAX],EDX
     *         // 004945F7    05 4C010000     ADD EAX,14C
     *         // 004945FC    49              DEC ECX
     *         // 004945FD    75 F3           JNZ SHORT VFP9.004945F2
     *         // 004945FF    C3              RETN
     *
     *         // fix to:
     *         // 004945DF    807C3E CC 00    CMP BYTE PTR DS:[ESI+EDI-34],0
     *         // 004945E4    74 03           JE SHORT VFP9.004945E9
     *         // 004945E6    03143E          ADD EDX,DWORD PTR DS:[ESI+EDI]
     *         // 004945E9    8B48 20         MOV ECX,DWORD PTR DS:[EAX+20]
     *         // 004945EC    E3 11           JECXZ SHORT VFP9.004945FF
     *         // 004945EE    8B40 24         MOV EAX,DWORD PTR DS:[EAX+24]
     *         // 004945F1    8B00            MOV EAX,DWORD PTR DS:[EAX]
     *         // 004945F3    03C7            ADD EAX,EDI
     *         // 004945F5    2950 F8         SUB DWORD PTR DS:[EAX-8],EDX
     *         // 004945F8    2910            SUB DWORD PTR DS:[EAX],EDX
     *         // 004945FA    83C0 38         ADD EAX,38
     *         // 004945FD    E2 F4           LOOPD SHORT VFP9.004945F3
     *         // 004945FF    C3              RETN

     
     PRIVATE m.q_str2
     m.q_str2=REPL(CHR(0),0x100000-0x080000)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x080000,@m.q_str2,LEN(m.q_str2),0)

     PRIVATE m.q_p2_nn
     m.q_p2_nn=1

     DO WHILE .T.

        PRIVATE m.q_p2
        m.q_p2=AT(CHR(0x05)+;
           CHR(0x14)+;
           CHR(0x01)+;
           CHR(0x00)+;
           CHR(0x00)+;
           CHR(0x29)+;
           CHR(0x50)+;
           CHR(0xf8)+;
           CHR(0x29)+;
           CHR(0x10),m.q_str2,m.q_p2_nn)
        IF !m.q_p2>0
           m.q_vfp9fixreportfooter=.F.
           RETU m.q_vfp9fixreportfooter
        ENDIF
        m.q_p2=m.q_p2-0x0e

        IF !(SUBS(m.q_str2,m.q_p2+0x0e,1)==CHR(0x05).AND.;
              SUBS(m.q_str2,m.q_p2+0x0f,1)==CHR(0x14).AND.;
              SUBS(m.q_str2,m.q_p2+0x10,1)==CHR(0x01).AND.;
              SUBS(m.q_str2,m.q_p2+0x11,1)==CHR(0x00).AND.;
              SUBS(m.q_str2,m.q_p2+0x12,1)==CHR(0x00).AND.;
              SUBS(m.q_str2,m.q_p2+0x13,1)==CHR(0x29).AND.;
              SUBS(m.q_str2,m.q_p2+0x14,1)==CHR(0x50).AND.;
              SUBS(m.q_str2,m.q_p2+0x15,1)==CHR(0xf8).AND.;
              SUBS(m.q_str2,m.q_p2+0x16,1)==CHR(0x29).AND.;
              SUBS(m.q_str2,m.q_p2+0x17,1)==CHR(0x10))
           m.q_p2_nn=m.q_p2_nn+1
           LOOP
        ENDIF

        EXIT

     ENDDO

     
     * OldProtect=0x20; // PAGE_EXECUTE_READ
     * VirtualProtect(p1,0x20,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
     * *(p1+0x03)=0x50;
     * *(p1+0x04)=0xBF;
     * *(p1+0x05)=0x14;
     * *(p1+0x06)=0x01;
     * *(p1+0x07)=0x00;
     * *(p1+0x08)=0x00;
     * *(p1+0x17)=0x33;
     * *(p1+0x18)=0xFF;
     * *(p1+0x19)=0x58;
     * VirtualProtect(p1,0x20,OldProtect,&OldProtect);
     *
     * OldProtect=0x20; // PAGE_EXECUTE_READ
     * VirtualProtect(p2,0x20,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
     * *(p2+0x00)=0x80;
     * *(p2+0x01)=0x7C;
     * *(p2+0x02)=0x3E;
     * *(p2+0x03)=0xCC;
     * *(p2+0x04)=0x00;
     * *(p2+0x05)=0x74;
     * *(p2+0x06)=0x03;
     * *(p2+0x07)=0x03;
     * *(p2+0x08)=0x14;
     * *(p2+0x09)=0x3E;
     * *(p2+0x0A)=0x8B;
     * *(p2+0x0B)=0x48;
     * *(p2+0x0C)=0x20;
     * *(p2+0x0D)=0xE3;
     * *(p2+0x0E)=0x11;
     * *(p2+0x0F)=0x8B;
     * *(p2+0x10)=0x40;
     * *(p2+0x11)=0x24;
     * *(p2+0x12)=0x8B;
     * *(p2+0x13)=0x00;
     * *(p2+0x14)=0x03;
     * *(p2+0x15)=0xC7;
     * *(p2+0x16)=0x29;
     * *(p2+0x17)=0x50;
     * *(p2+0x18)=0xF8;
     * *(p2+0x19)=0x29;
     * *(p2+0x1A)=0x10;
     * *(p2+0x1B)=0x83;
     * *(p2+0x1C)=0xC0;
     * *(p2+0x1D)=0x38;
     * *(p2+0x1E)=0xE2;
     * *(p2+0x1F)=0xF4;
     * VirtualProtect(p2,0x20,OldProtect,&OldProtect);

     PRIVATE m.q_str1
     m.q_str1=REPL(CHR(0),0x20)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x080000+m.q_p1-1+0x00,@m.q_str1,LEN(m.q_str1),0)
     m.q_str1=STUFF(m.q_str1,0x03+1,1,CHR(0x50))
     m.q_str1=STUFF(m.q_str1,0x04+1,1,CHR(0xbf))
     m.q_str1=STUFF(m.q_str1,0x05+1,1,CHR(0x14))
     m.q_str1=STUFF(m.q_str1,0x06+1,1,CHR(0x01))
     m.q_str1=STUFF(m.q_str1,0x07+1,1,CHR(0x00))
     m.q_str1=STUFF(m.q_str1,0x08+1,1,CHR(0x00))
     m.q_str1=STUFF(m.q_str1,0x17+1,1,CHR(0x33))
     m.q_str1=STUFF(m.q_str1,0x18+1,1,CHR(0xff))
     m.q_str1=STUFF(m.q_str1,0x19+1,1,CHR(0x58))

     PRIVATE m.q_str2
     m.q_str2=CHR(0x80)+;
        CHR(0x7c)+;
        CHR(0x3e)+;
        CHR(0xcc)+;
        CHR(0x00)+;
        CHR(0x74)+;
        CHR(0x03)+;
        CHR(0x03)+;
        CHR(0x14)+;
        CHR(0x3e)+;
        CHR(0x8b)+;
        CHR(0x48)+;
        CHR(0x20)+;
        CHR(0xe3)+;
        CHR(0x11)+;
        CHR(0x8b)+;
        CHR(0x40)+;
        CHR(0x24)+;
        CHR(0x8b)+;
        CHR(0x00)+;
        CHR(0x03)+;
        CHR(0xc7)+;
        CHR(0x29)+;
        CHR(0x50)+;
        CHR(0xf8)+;
        CHR(0x29)+;
        CHR(0x10)+;
        CHR(0x83)+;
        CHR(0xc0)+;
        CHR(0x38)+;
        CHR(0xe2)+;
        CHR(0xf4)

     PRIVATE m.q_oldprotect1
     m.q_oldprotect1=0x20 && PAGE_EXECUTE_READ
     =virtualprotect(m.q_hmodule0+0x080000+m.q_p1-1,0x20,0x40,@m.q_oldprotect1) && PAGE_EXECUTE_READWRITE

     PRIVATE m.q_oldprotect2
     m.q_oldprotect2=0x20 && PAGE_EXECUTE_READ
     =virtualprotect(m.q_hmodule0+0x080000+m.q_p2-1,0x20,0x40,@m.q_oldprotect2) && PAGE_EXECUTE_READWRITE

     =writeprocessmemory(getcurrentprocess(),m.q_hmodule0+0x080000+m.q_p1-1+0x00,m.q_str1,LEN(m.q_str1),0)
     =writeprocessmemory(getcurrentprocess(),m.q_hmodule0+0x080000+m.q_p2-1+0x00,m.q_str2,LEN(m.q_str2),0)

     =virtualprotect(m.q_hmodule0+0x080000+m.q_p1-1,0x20,m.q_oldprotect1,@m.q_oldprotect1)
     =virtualprotect(m.q_hmodule0+0x080000+m.q_p2-1,0x20,m.q_oldprotect2,@m.q_oldprotect2)

     m.q_vfp9fixreportfooter=.T.
     RETU m.q_vfp9fixreportfooter

     * END OF PROC F_VFP9FIXREPORTFOOTER.


     6, Recommend to add the following code to the start program:

     * VFP9FixReportFooter

     #IF ROUND(VAL(CHRTRAN(UPPE(VERSION()),"MICROSOFTVISUALFOXPRO","")),2)=9.0
     =f_vfp9fixreportfooter()
     #ENDI

     Now in vfp9, the report is correct too.

     Please refer to the picture testreport9-vfp9fix.jpg:


4. APPLIES TO:

     VFP 9.0.0.2412
     VFP 9.0.0.3504 (SP1)
     VFP 9.0.0.4611 (SP2)
     VFP 9.0.0.5015 (SP2)
     VFP 9.0.0.5411 (SP2)
     VFP 9.0.0.5721 (SP2)
     VFP 9.0.0.5815 (SP2)
     VFP 9.0.0.6303 (SP2)
     VFP 9.0.0.6602 (SP2)
     VFP 9.0.0.7423 (SP2)

     The bug has been fixed in VFP Advanced.


5. REFERENCE WEBSITES:

     1, baiyujia.com:
     http://www.baiyujia.com

     2, meizvfp.com:
     http://www.mzvfp.com/read.php?tid=84717
     http://www.mzvfp.com/read.php?tid=85037


6. OTHER:

     For reference only, there is no guarantees.

     Any questions or suggestions, please send me an email at ccb2000@163.com.