------------------------------------------------------------
[BUG/PRB.] VFP 9.0 FIX - LARGE PROCEDURE IN THE FORM
January 2026
------------------------------------------------------------
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.
|