I have some Fox classes that run in several modes.

  • The normal fox interactive design environment
  • In a runtime Multithreaded DLL from the fox interactive environment
  • In a runtime Multithreaded DLL from within a client application (like windows explorer)

 

The error methods of those classes do different things depending on _vfp.StartMode(“Returns the Fox Start Mode. 0=None, 1=LocalServer, 2=Runtime EXE Server, 3=Runtime DLL Server, 4=VFP Runtime App, 5=Runtime MTDLL Server”)

 

VFP MT DLLs do not normally do UI (User Interface) because they’re targeted to be used in server applications, such as web servers which have no UI. But you can still call MessageBox by using DECLARE DLL as shown.

 

Many windows APIs that take strings as parameters have two versions: ANSI and Wide char. The ANSI ones use a single byte per character, and the Wide versions use Unicode. If you single step through the assembly code you can see that one version just converts the parameter for the other and then calls it.

 

From winuser.h:

 

#ifdef UNICODE

#define MessageBox  MessageBoxW

#else

#define MessageBox  MessageBoxA

#endif // !UNICODE

 

You can see that both MessageBoxA and MessageBoxW are exported from user32.dll:

link /dump /exports c:\windows\system32\user32.dll

 

The OutputDebugString call outputs to any attached debugger. I typically run with Visual Studio as the debugger, so its output window shows a log of what’s happening.

 

The VFP program has a single PUBLIC integer variable called g_debugFlags which has up to 32 bits, each of which can indicate which things to log to the DebugOutputWindow and/or a logfile. Filtering the events to only those of interest reduces the noise.

 

I have both a RETRY and a RETURN statement: while at a breakpoint in the VFP debugger, I can change variable values or switch to the command window to open tables, etc. A RETRY will try again to execute the erroneous statement, and RETURN will skip that statement and proceed with the following one.

 

 

 

DEFINE CLASS ShellNode AS session

      PROCEDURE error(nError, cMethod, nLine)

            cStr=PROGRAM()+" "+MESSAGE()+" "+MESSAGE(1)+" "+TRANSFORM(nError)+" "+TRANSFORM(cMethod)+" "+TRANSFORM(nLine)

            ?cStr

            IF _vfp.StartMode=0

                  SET STEP ON && open debugger

                  RETRY && to retry statement that triggered err

                  RETURN && SET NEXT Stmt (Shift+Ctrl-F7 here will skip statement that triggered err

            ENDIF

            DECLARE integer MessageBoxA IN WIN32API integer,string,string,integer

            this.logit(cStr,.t.)

            nRet=MessageBoxA(0,cStr,PROGRAM(),2+512+32)

            DO CASE

            CASE nRet=3 &&Abort

                  COMRETURNERROR(PROGRAM(),cStr)

            CASE nRet=4 &&Retry

                  RETRY

            CASE nRet=5 &&Ignore

                  RETURN

            ENDCASE

      PROCEDURE logit(cstr as String,fForce as Boolean)

            IF BITAND(DF_NSELOGFILE + DF_NSEVFP,g_debugflags)>0 OR fForce

                  DECLARE integer OutputDebugString IN WIN32API string

                  cstr=TRANSFORM(DATETIME())+" "+cstr+CHR(13)

                  OutputDebugString(cstr)

                  IF BITAND(DF_NSELOGFILE,g_debugflags)>0 OR fForce

                        STRTOFILE(cstr,LOGFILE,.t.)

                  ENDIF

            ENDIF

ENDDEFINE

 

 

 

63067