------------------------------------------------------------ [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. |