------------------------------------------------------------
                     [BUG/PRB.] VFP 9.0 FIX - LARGE PROCEDURE IN THE FORM
                                 January 2024
                 ------------------------------------------------------------
                                     CCB



1. BUG:

     In vfp9, the procedure size can greater than 64KB.
     But if there is a large procedure in the form, sometimes the form can't run correctly.

     There is a program for test:

     *PROC testlargeform

     SET STEP OFF
     SET ECHO OFF
     SET DEBUG OFF
     SET ESCAPE OFF
     SET TALK OFF
     SET SAFETY OFF

     _SCREEN.VISIBLE=.T.
     _SCREEN.WINDOWSTATE=2

     PRIVATE m.x2
     m.x2=""

     COMPILE FORM testlargeform.scx
     =MESSAGEBOX("Now the form file testlargeform.scx is good."+CHR(13)+;
        "We will run DO FORM testlargeform.scx and there is no problem.",0,"TEST LARGEFORM")
     DO FORM testlargeform.scx

     =MESSAGEBOX("Please make some changes."+CHR(13)+;
        "For example, Comment or Uncomment some statements.",0,"TEST LARGEFORM")
     MODIFY FORM testlargeform.scx method INIT

     COPY FILE testlargeform.scx TO testlargeform_bad.scx
     COPY FILE testlargeform.sct TO testlargeform_bad.sct
     USE testlargeform_bad.scx
     LOCATE FOR objname="Form1"
     =STRTOFILE(objcode,"testlargeform_bad.fxp")
     USE

     COPY FILE testlargeform.scx TO testlargeform_good.scx
     COPY FILE testlargeform.sct TO testlargeform_good.sct
     COMPILE FORM testlargeform_good.scx
     USE testlargeform_good.scx
     LOCATE FOR objname="Form1"
     =STRTOFILE(objcode,"testlargeform_good.fxp")
     USE

     USE testlargeform.scx
     LOCATE FOR objname="Form1"
     PRIVATE m.q_com
     m.q_com=methods
     PRIVATE m.q_procedures
     m.q_procedures=""
     DO WHILE AT("PROCEDURE ",m.q_com)>0
        m.q_com=SUBS(m.q_com,AT("PROCEDURE ",m.q_com))
        m.q_procedures=m.q_procedures+LEFT(m.q_com,AT(CHR(13),m.q_com))
        m.q_com=SUBS(m.q_com,AT(CHR(13),m.q_com)+1)
     ENDDO
     USE
     m.q_procedures=STRTRAN(m.q_procedures,"PROCEDURE Init","PROCEDURE Init (LARGE PROCEDURE)")

     IF FILETOSTR("testlargeform_bad.fxp")==FILETOSTR("testlargeform_good.fxp")
        =MESSAGEBOX("It seems the form file testlargeform.scx is good."+CHR(13)+;
           m.q_procedures+;
           "We will run DO FORM testlargeform.scx and there is no problem.",0,"TEST LARGEFORM")
        DO FORM testlargeform.scx
     ELSE
        =MESSAGEBOX("Now the form file testlargeform.scx is bad."+CHR(13)+;
           m.q_procedures+;
           "If we run DO FORM testlargeform.scx then VFP will crash.",16,"TEST LARGEFORM")
        DO FORM testlargeform.scx
     ENDIF

     RETURN

     * END OF PROC TESTLARGEFORM.

     In the testlargeform.scx:

     PROCEDURE Load
     SET TALK OFF
     ?"Load"
     ENDPROC

     PROCEDURE Init
     * Please make some changes.
     * For example, Comment or Uncomment some statements.
     SET TALK OFF
     SET TALK OFF
     SET TALK OFF
     ?"Init"
     PRIVATE m.x2
     m.x2="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     m.x2="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     ...
     m.x2="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     m.x2="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
     ENDPROC

     PROCEDURE Destroy
     SET TALK OFF
     ?"Destroy"
     ENDPROC

     The size of the procedure Init is about 100KB, it is a large procedure.


2. CAUSE:

     Please refer to the head of the testlargeform_bad.fxp:

     00000000:  FE F2 FF 20-02 01 00 00-00 6F CA 01-00 6F CA 01  ................
     00000010:  00 00 00 00-00 00 00 00-00 00 00 00-00 00 00 00  ................
     00000020:  00 00 00 00-00 00 00 EB-F4 03 00 00-00 25 00 00  ................
     00000030:  00 ED C1 01-00 00 00 00-00 06 CA 01-00 F6 03 00  ................
     00000040:  00 1A C2 01-00 00 00 00-00 00 00 00-00 85 00 00  ................
     00000050:  03 00 00 00-03 00 55 00-00 00 00 1C-00 00 00 06  ................
     00000060:  00 47 32 1F-FE 13 00 02-F8 03 01 FC-D9 07 00 44  ................
     00000070:  65 73 74 72-6F 79 FD FE-03 00 55 00-00 00 00 6C  ................
     00000080:  C1 01 00 06-00 47 32 1F-FE 06 00 47-32 1F FE 06  ................
     00000090:  00 47 32 1F-FE 06 00 47-32 1F FE 10-00 02 F8 03  ................
     000000A0:  01 FC D9 04-00 49 6E 69-74 FD FE 09-00 35 F5 0D  ................
     000000B0:  F7 00 00 FE-73 00 54 F5-0D F7 00 00-10 FC D9 64  ................
     000000C0:  00 41 41 41-41 41 41 41-41 41 41 41-41 41 41 41  .AAAAAAAAAAAAAAA
     000000D0:  41 41 41 41-41 41 41 41-41 41 41 41-41 41 41 41  AAAAAAAAAAAAAAAA
     000000E0:  41 41 41 41-41 41 41 41-41 41 41 41-41 41 41 41  AAAAAAAAAAAAAAAA
     000000F0:  41 41 41 41-41 41 41 41-41 41 41 41-41 41 41 41  AAAAAAAAAAAAAAAA
     ............................................................................

     00000-00028 app head, 0x29 bytes
     00029-0004D fxp head, 0x25 bytes
     0004E-00058 empty program, 0x0B bytes
     00059-0007C procedure Destroy, 0x24 bytes
     0007D-1C1F4 procedure INIT, 0x1C178 bytes
     1C1F5-1C215 procedure Load, 21 bytes

     But in the tail of the testlargeform_bad.fxp:

     0001C210:                    07 00-44 65 73 74-72 6F 79 4C          Destroy.
     0001C220:  00 00 00 00-00 FF FF 04-00 49 6E 69-74 54 00 00  .........Init...
     0001C230:  00 00 00 FF-FF 04 00 4C-6F 61 64 CC-C1 01 00 00  .......Load.....
     0001C240:  00 FF FF                                         ...

     1C216-1C217 size of procedure name: 0x07 bytes
     1C218-1C21E procedure name: Destroy
     1C21F-1C222 start offset of procedure Destroy: 0x004C <> 0x59 - 0x29?
     1C223-1C224 class flag: 0x0000
     1C225-1C226 class order: 0xFFFF

     1C227-1C228 size of procedure name: 0x04 bytes
     1C229-1C22C procedure name: Init
     1C22D-1C230 start offset of procedure Init: 0x0054 == 0x7D - 0x29
     1C231-1C232 class flag: 0x0000
     1C233-1C234 class order: 0xFFFF

     1C235-1C236 size of procedure name: 0x04 bytes
     1C237-1C23A procedure name: Load
     1C23B-1C23E start offset of procedure Load: 0x1C1CC == 0x1C1F5 - 0x29
     1C23F-1C240 class flag: 0x0000
     1C241-1C242 class order: 0xFFFF

     The start offset of the procedure Destroy (before the LARGE procedure Init) is not equal to 0x30 (0x59 - 0x29),
     so the file is wrong, it can't run correctly.


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 VFP9toLargeProcedure()
     {
         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=0x040000;i<0x280000;i++)
         {
             p1=hmodule0+i;
             if (*(p1+0x00)==0x56 &&
                 *(p1+0x01)==0x8D &&
                 *(p1+0x02)==0x74 &&
                 *(p1+0x03)==0x19 &&
                 *(p1+0x04)==0x02 &&
                 *(p1+0x05)==0x81 &&
                 *(p1+0x06)==0xFE &&
                 *(p1+0x07)==0xE8 &&
                 *(p1+0x08)==0xFD &&
                 *(p1+0x09)==0x00 &&
                 *(p1+0x0A)==0x00 &&
                 *(p1+0x0B)==0x57)
             {

                 // fix vfp9.exe, vfp9r.dll
                 // 00464C72: 8B88F0020000                 mov       ecx,[eax][0000002F0]
                 // 00464C78: 56                           push      esi
                 // 00464C79: 8D741902                     lea       esi,[ecx][ebx][00002]
                 // 00464C7D: 81FEE8FD0000                 cmp       esi,00000FDE8
                 // 00464C83: 57                           push      edi
                 // 00464C84: 0F83661B1000                 jae       0005667F0

                 // fix to:
                 // 00464C72: 8B88F0020000                 mov       ecx,[eax][0000002F0]
                 // 00464C78: 56                           push      esi
                 // 00464C79: 8D741902                     lea       esi,[ecx][ebx][00002]
                 // 00464C7D: 81FE06000000                 cmp       esi,000000006
                 // 00464C83: 57                           push      edi
                 // 00464C84: 0F83661B1000                 jae       0005667F0

                 for (i=i+0x10;i<0x280000;i++)
                 {
                     p2=hmodule0+i;
                     if (*(p2+0x00)==0x56 &&
                         *(p2+0x01)==0x8D &&
                         *(p2+0x02)==0x74 &&
                         *(p2+0x03)==0x19 &&
                         *(p2+0x04)==0x02 &&
                         *(p2+0x05)==0x81 &&
                         *(p2+0x06)==0xFE &&
                         *(p2+0x07)==0xE8 &&
                         *(p2+0x08)==0xFD &&
                         *(p2+0x09)==0x00 &&
                         *(p2+0x0A)==0x00 &&
                         *(p2+0x0B)==0x57)
                     {

                         // fix vfp9.exe, vfp9r.dll
                         // 00547856: 8B887C020000                 mov       ecx,[eax][00000027C]
                         // 0054785C: 56                           push      esi
                         // 0054785D: 8D741902                     lea       esi,[ecx][ebx][00002]
                         // 00547861: 81FEE8FD0000                 cmp       esi,00000FDE8
                         // 00547867: 57                           push      edi
                         // 00547868: 0F83B2EF0100                 jae       000566820

                         // fix to:
                         // 00547856: 8B887C020000                 mov       ecx,[eax][00000027C]
                         // 0054785C: 56                           push      esi
                         // 0054785D: 8D741902                     lea       esi,[ecx][ebx][00002]
                         // 00547861: 81FE06000000                 cmp       esi,000000006
                         // 00547867: 57                           push      edi
                         // 00547868: 0F83B2EF0100                 jae       000566820

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

                         OldProtect=0x20; // PAGE_EXECUTE_READ
                         VirtualProtect(p1,0x10,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
                         *(p1+0x07)=0x06;
                         *(p1+0x08)=0x00;
                         VirtualProtect(p1,0x10,OldProtect,&OldProtect);

                         OldProtect=0x20; // PAGE_EXECUTE_READ
                         VirtualProtect(p2,0x10,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
                         *(p2+0x07)=0x06;
                         *(p2+0x08)=0x00;
                         VirtualProtect(p2,0x10,OldProtect,&OldProtect);
                         break;
                     }
                 }
                 break;
             }
         }
     }

     FoxInfo myFoxInfo[]={
     {"VFP9toLargeProcedure",(FPFI)VFP9toLargeProcedure,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_vfp9tolargeprocedurewithdll.prg:

     *PROC f_vfp9tolargeprocedurewithdll

     * VFP 9.0 to Large Procedure with vfp9fix.dll
     * ccb2000@163.com, 2012.3

     =f_vfp9fixmacrosubstitutionwithdll()

     PRIVATE m.q_vfp9tolargeprocedure
     m.q_vfp9tolargeprocedure=.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 vfp9tolargeprocedure(1)
        ENDI

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

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

        IF m.q_errnum#0
           m.q_vfp9tolargeprocedure=.F.
           RETU m.q_vfp9tolargeprocedure
        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_vfp9tolargeprocedure=.F.
           RETU m.q_vfp9tolargeprocedure
        ENDI

        m.q_vfp9tolargeprocedure=.T.
        RETU m.q_vfp9tolargeprocedure

     ENDI

     m.q_vfp9tolargeprocedure=.T.
     RETU m.q_vfp9tolargeprocedure

     * END OF PROC F_VFP9TOLARGEPROCEDUREWITHDLL.


     5, Please refer to the file f_vfp9tolargeprocedure.prg:

     *PROC f_vfp9tolargeprocedure

     * VFP 9.0 to Large Procedure
     * ccb2000@163.com, 2012.3

     =f_vfp9fixmacrosubstitution()

     PRIVATE m.q_vfp9tolargeprocedure
     m.q_vfp9tolargeprocedure=.T.

     IF !ROUND(VAL(CHRTRAN(UPPE(VERSION()),"MICROSOFTVISUALFOXPRO","")),2)=9.0
        m.q_vfp9tolargeprocedure=.T.
        RETU m.q_vfp9tolargeprocedure
     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_vfp9tolargeprocedure=.F.
        RETU m.q_vfp9tolargeprocedure
     ENDIF


     * for (i=0x040000;i<0x280000;i++)
     * {
     *     p1=hmodule0+i;
     *     if (*(p1+0x00)==0x56 &&
     *         *(p1+0x01)==0x8D &&
     *         *(p1+0x02)==0x74 &&
     *         *(p1+0x03)==0x19 &&
     *         *(p1+0x04)==0x02 &&
     *         *(p1+0x05)==0x81 &&
     *         *(p1+0x06)==0xFE &&
     *         *(p1+0x07)==0xE8 &&
     *         *(p1+0x08)==0xFD &&
     *         *(p1+0x09)==0x00 &&
     *         *(p1+0x0A)==0x00 &&
     *         *(p1+0x0B)==0x57)
     *     {
     *
     *         // fix vfp9.exe, vfp9r.dll
     *         // 00464C72: 8B88F0020000                 mov       ecx,[eax][0000002F0]
     *         // 00464C78: 56                           push      esi
     *         // 00464C79: 8D741902                     lea       esi,[ecx][ebx][00002]
     *         // 00464C7D: 81FEE8FD0000                 cmp       esi,00000FDE8
     *         // 00464C83: 57                           push      edi
     *         // 00464C84: 0F83661B1000                 jae       0005667F0
     *
     *         // fix to:
     *         // 00464C72: 8B88F0020000                 mov       ecx,[eax][0000002F0]
     *         // 00464C78: 56                           push      esi
     *         // 00464C79: 8D741902                     lea       esi,[ecx][ebx][00002]
     *         // 00464C7D: 81FE06000000                 cmp       esi,000000006
     *         // 00464C83: 57                           push      edi
     *         // 00464C84: 0F83661B1000                 jae       0005667F0

     PRIVATE m.q_str1
     m.q_str1=REPL(CHR(0),0x280000-0x040000)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x040000,@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(0x56)+;
           CHR(0x8d)+;
           CHR(0x74)+;
           CHR(0x19)+;
           CHR(0x02)+;
           CHR(0x81)+;
           CHR(0xfe)+;
           CHR(0xe8)+;
           CHR(0xfd)+;
           CHR(0x00)+;
           CHR(0x00)+;
           CHR(0x57),m.q_str1,m.q_p1_nn)
        IF !m.q_p1>0
           m.q_vfp9tolargeprocedure=.F.
           RETU m.q_vfp9tolargeprocedure
        ENDIF
        m.q_p1=m.q_p1-0x00

        IF !(SUBS(m.q_str1,m.q_p1+0x00,1)==CHR(0x56).AND.;
              SUBS(m.q_str1,m.q_p1+0x01,1)==CHR(0x8d).AND.;
              SUBS(m.q_str1,m.q_p1+0x02,1)==CHR(0x74).AND.;
              SUBS(m.q_str1,m.q_p1+0x03,1)==CHR(0x19).AND.;
              SUBS(m.q_str1,m.q_p1+0x04,1)==CHR(0x02).AND.;
              SUBS(m.q_str1,m.q_p1+0x05,1)==CHR(0x81).AND.;
              SUBS(m.q_str1,m.q_p1+0x06,1)==CHR(0xfe).AND.;
              SUBS(m.q_str1,m.q_p1+0x07,1)==CHR(0xe8).AND.;
              SUBS(m.q_str1,m.q_p1+0x08,1)==CHR(0xfd).AND.;
              SUBS(m.q_str1,m.q_p1+0x09,1)==CHR(0x00).AND.;
              SUBS(m.q_str1,m.q_p1+0x0a,1)==CHR(0x00).AND.;
              SUBS(m.q_str1,m.q_p1+0x0b,1)==CHR(0x57))
           m.q_p1_nn=m.q_p1_nn+1
           LOOP
        ENDIF

        EXIT

     ENDDO


     * for (i=i+0x10;i<0x280000;i++)
     * {
     *     p2=hmodule0+i;
     *     if (*(p2+0x00)==0x56 &&
     *         *(p2+0x01)==0x8D &&
     *         *(p2+0x02)==0x74 &&
     *         *(p2+0x03)==0x19 &&
     *         *(p2+0x04)==0x02 &&
     *         *(p2+0x05)==0x81 &&
     *         *(p2+0x06)==0xFE &&
     *         *(p2+0x07)==0xE8 &&
     *         *(p2+0x08)==0xFD &&
     *         *(p2+0x09)==0x00 &&
     *         *(p2+0x0A)==0x00 &&
     *         *(p2+0x0B)==0x57)
     *     {
     *
     *         // fix vfp9.exe, vfp9r.dll
     *         // 00547856: 8B887C020000                 mov       ecx,[eax][00000027C]
     *         // 0054785C: 56                           push      esi
     *         // 0054785D: 8D741902                     lea       esi,[ecx][ebx][00002]
     *         // 00547861: 81FEE8FD0000                 cmp       esi,00000FDE8
     *         // 00547867: 57                           push      edi
     *         // 00547868: 0F83B2EF0100                 jae       000566820
     *
     *         // fix to:
     *         // 00547856: 8B887C020000                 mov       ecx,[eax][00000027C]
     *         // 0054785C: 56                           push      esi
     *         // 0054785D: 8D741902                     lea       esi,[ecx][ebx][00002]
     *         // 00547861: 81FE06000000                 cmp       esi,000000006
     *         // 00547867: 57                           push      edi
     *         // 00547868: 0F83B2EF0100                 jae       000566820

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

     PRIVATE m.q_p2_nn
     m.q_p2_nn=2

     DO WHILE .T.

        PRIVATE m.q_p2
        m.q_p2=AT(CHR(0x56)+;
           CHR(0x8d)+;
           CHR(0x74)+;
           CHR(0x19)+;
           CHR(0x02)+;
           CHR(0x81)+;
           CHR(0xfe)+;
           CHR(0xe8)+;
           CHR(0xfd)+;
           CHR(0x00)+;
           CHR(0x00)+;
           CHR(0x57),m.q_str2,m.q_p2_nn)
        IF !m.q_p2>0
           m.q_vfp9tolargeprocedure=.F.
           RETU m.q_vfp9tolargeprocedure
        ENDIF
        m.q_p2=m.q_p2-0x00

        IF !(SUBS(m.q_str2,m.q_p2+0x00,1)==CHR(0x56).AND.;
              SUBS(m.q_str2,m.q_p2+0x01,1)==CHR(0x8d).AND.;
              SUBS(m.q_str2,m.q_p2+0x02,1)==CHR(0x74).AND.;
              SUBS(m.q_str2,m.q_p2+0x03,1)==CHR(0x19).AND.;
              SUBS(m.q_str2,m.q_p2+0x04,1)==CHR(0x02).AND.;
              SUBS(m.q_str2,m.q_p2+0x05,1)==CHR(0x81).AND.;
              SUBS(m.q_str2,m.q_p2+0x06,1)==CHR(0xfe).AND.;
              SUBS(m.q_str2,m.q_p2+0x07,1)==CHR(0xe8).AND.;
              SUBS(m.q_str2,m.q_p2+0x08,1)==CHR(0xfd).AND.;
              SUBS(m.q_str2,m.q_p2+0x09,1)==CHR(0x00).AND.;
              SUBS(m.q_str2,m.q_p2+0x0a,1)==CHR(0x00).AND.;
              SUBS(m.q_str2,m.q_p2+0x0b,1)==CHR(0x57))
           m.q_p2_nn=m.q_p2_nn+1
           LOOP
        ENDIF

        EXIT

     ENDDO


     * OldProtect=0x20; // PAGE_EXECUTE_READ
     * VirtualProtect(p1,0x10,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
     * *(p1+0x07)=0x06;
     * *(p1+0x08)=0x00;
     * VirtualProtect(p1,0x10,OldProtect,&OldProtect);

     * OldProtect=0x20; // PAGE_EXECUTE_READ
     * VirtualProtect(p2,0x10,0x40,&OldProtect); // PAGE_EXECUTE_READWRITE
     * *(p2+0x07)=0x06;
     * *(p2+0x08)=0x00;
     * VirtualProtect(p2,0x10,OldProtect,&OldProtect);

     PRIVATE m.q_str1
     m.q_str1=REPL(CHR(0),0x10)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x040000+m.q_p1-1+0x00,@m.q_str1,LEN(m.q_str1),0)
     m.q_str1=STUFF(m.q_str1,0x07+1,1,CHR(0x06))
     m.q_str1=STUFF(m.q_str1,0x08+1,1,CHR(0x00))

     PRIVATE m.q_str2
     m.q_str2=REPL(CHR(0),0x10)
     =readprocessmemory(getcurrentprocess(),m.q_hmodule0+0x040000+m.q_p2-1+0x00,@m.q_str2,LEN(m.q_str2),0)
     m.q_str2=STUFF(m.q_str2,0x07+1,1,CHR(0x06))
     m.q_str2=STUFF(m.q_str2,0x08+1,1,CHR(0x00))

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

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

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

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

     m.q_vfp9tolargeprocedure=.T.
     RETU m.q_vfp9tolargeprocedure

     * END OF PROC F_VFP9TOLARGEPROCEDURE.


     6, Recommend to add the following code to the program file vfpstart.prg:

     * VFP9toLargeProcedure

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

     then build the executable file vfpstart.exe from the program file vfpstart.prg:
     BUILD PROJECT vfpstart.pjx FROM vfpstart.prg
     BUILD EXE vfpstart.exe FROM vfpstart.pjx

     then add the following code to the file config.fpw:
     COMMAND=DO vfpstart.exe

     then when we run:
     VFP9.EXE -Cconfig.fpw

     vfp will run DO vfpstart.exe first,
     now if there is a large procedure in the form, the form can run correctly too.


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
     http://www.baiyujia.com/vfpdocuments/f_vfp9fix223.asp


6. OTHER:

     For reference only, there is no guarantees.

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