@@ -319,6 +319,82 @@ Pixels[END RESERVED6]
319319[UNIQUEID] RESERVED
320320[OBJNAME] events
321321
322+ [ RECORD]
323+ [PLATFORM] WINDOWS
324+ [UNIQUEID] _3CV0J32BY
325+ [CLASS] form
326+ [BASECLASS] form
327+ [OBJNAME] frmerrorlist
328+ [START PROPERTIES]
329+ AutoCenter = .T.
330+ Caption = "ParallelFox Worker Errors"
331+ DoCreate = .T.
332+ Height = 480
333+ Name = "frmerrorlist"
334+ Width = 640
335+ _memberdata = <VFPData><memberdata name="displayerror" display="DisplayError"/><memberdata name="cerrorlist" display="cErrorList"/></VFPData>
336+ cerrorlist =
337+ [END PROPERTIES]
338+ [START METHODS]
339+ PROCEDURE displayerror
340+ * Display error in list.
341+ Lparameters lnError, lcMethod, lnLine, lcMessage, lcCode
342+ Local lcErrorMsg
343+
344+ Text to lcErrorMsg TextMerge NoShow
345+ Error: <<lnError>>
346+ Message: <<lcMessage>>
347+ Method: <<lcMethod>>
348+ Line: <<lnLine>>
349+ <<Replicate("-",100)>>
350+
351+ EndText
352+
353+ ThisForm.cErrorList = ThisForm.cErrorList + lcErrorMsg
354+ * ThisForm.edtErrorList.Value = ThisForm.edtErrorList.Value + lcErrorMsg
355+ ThisForm.edtErrorList.Refresh()
356+
357+
358+ ENDPROC
359+ [END METHODS]
360+ [START RESERVED1]
361+ Class[END RESERVED1]
362+ [START RESERVED2]
363+ 2[END RESERVED2]
364+ [START RESERVED3]
365+ *displayerror Display error in list.
366+ _memberdata XML Metadata for customizable properties
367+ cerrorlist List of errors.
368+ [END RESERVED3]
369+ [START RESERVED6]
370+ Pixels[END RESERVED6]
371+
372+ [ RECORD]
373+ [PLATFORM] WINDOWS
374+ [UNIQUEID] _3CV0J60T9
375+ [CLASS] editbox
376+ [BASECLASS] editbox
377+ [OBJNAME] edtErrorList
378+ [PARENT] frmerrorlist
379+ [START PROPERTIES]
380+ Anchor = 15
381+ ControlSource = "Thisform.cErrorList"
382+ Height = 478
383+ Left = 1
384+ Name = "edtErrorList"
385+ ReadOnly = .T.
386+ Top = 1
387+ Width = 638
388+ [END PROPERTIES]
389+
390+ [ RECORD]
391+ [PLATFORM] COMMENT
392+ [UNIQUEID] RESERVED
393+ [OBJNAME] frmerrorlist
394+ [START PROPERTIES]
395+ Arial, 0, 9, 5, 15, 12, 32, 3, 0
396+ [END PROPERTIES]
397+
322398[ RECORD]
323399[PLATFORM] WINDOWS
324400[UNIQUEID] _2XO1B7PVN
@@ -662,11 +738,10 @@ Pixels[END RESERVED6]
662738[BASECLASS] custom
663739[OBJNAME] parpoolmgr
664740[START PROPERTIES]
665-
666741Name = "parpoolmgr"
667- _memberdata = 1007<VFPData><memberdata name="ncpucount" display="nCPUCount"/><memberdata name="nworkercount" display="nWorkerCount"/><memberdata name="startworkers" display="StartWorkers"/><memberdata name="workers" display="Workers"/><memberdata name="nbusyworkers" display="nBusyWorkers"/><memberdata name="queuecommand" display="QueueCommand"/><memberdata name="processqueue" display="ProcessQueue"/><memberdata name="commandqueue" display="CommandQueue"/><memberdata name="ldebugmode" display="lDebugMode"/><memberdata name="stopworkers" display="StopWorkers"/><memberdata name="handleerror" display="HandleError"/><memberdata name="conerror" display="cOnError"/><memberdata name="clearqueue" display="ClearQueue"/><memberdata name="cworkercomprogid" display="cWorkerCOMProgID"/><memberdata name="cworkerclass" display="cWorkerClass"/><memberdata name="cworkerlibrary" display="cWorkerLibrary"/><memberdata name="nprocessing" display="nProcessing"/><memberdata name="setworkercount" display="SetWorkerCount"/></VFPData>
742+ _memberdata = 1115<VFPData><memberdata name="ncpucount" display="nCPUCount"/><memberdata name="nworkercount" display="nWorkerCount"/><memberdata name="startworkers" display="StartWorkers"/><memberdata name="workers" display="Workers"/><memberdata name="nbusyworkers" display="nBusyWorkers"/><memberdata name="queuecommand" display="QueueCommand"/><memberdata name="processqueue" display="ProcessQueue"/><memberdata name="commandqueue" display="CommandQueue"/><memberdata name="ldebugmode" display="lDebugMode"/><memberdata name="stopworkers" display="StopWorkers"/><memberdata name="handleerror" display="HandleError"/><memberdata name="conerror" display="cOnError"/><memberdata name="clearqueue" display="ClearQueue"/><memberdata name="cworkercomprogid" display="cWorkerCOMProgID"/><memberdata name="cworkerclass" display="cWorkerClass"/><memberdata name="cworkerlibrary" display="cWorkerLibrary"/><memberdata name="nprocessing" display="nProcessing"/><memberdata name="setworkercount" display="SetWorkerCount"/><memberdata name="displayerrors" display="DisplayErrors"/><memberdata name="oerrorlist" display="oErrorList"/></VFPData>
668743commandqueue =
669- conerror =
744+ conerror = This.DisplayErrors(nError, cMethod, nLine, cMessage, cCode)
670745cworkerclass = WorkerMgr
671746cworkercomprogid = ParallelFox.WorkerMgr
672747cworkerlibrary = WorkerMgr.vcx
@@ -675,6 +750,7 @@ nbusyworkers = 0
675750ncpucount = 0
676751nprocessing = 0
677752nworkercount = 0
753+ oerrorlist = .NULL.
678754workers = .NULL.
679755[END PROPERTIES]
680756[START PROTECTED]
@@ -702,6 +778,17 @@ This.CommandQueue = CreateObject("Collection")
702778
703779This.nProcessing = 0
704780ENDPROC
781+ PROCEDURE displayerrors
782+ * Default error handler displays list of errors from workers.
783+ Lparameters lnError, lcMethod, lnLine, lcMessage, lcCode
784+
785+ If Vartype(This.oErrorList) <> "O" or IsNull(This.oErrorList)
786+ This.oErrorList = NewObject("frmErrorList", "ParallelFox.vcx")
787+ This.oErrorList.Show()
788+ EndIf
789+
790+ This.oErrorList.DisplayError(lnError, lcMethod, lnLine, lcMessage, lcCode)
791+ ENDPROC
705792PROCEDURE handleerror
706793* Global error handler. Set up with Parallel.OnError()
707794Lparameters nError, cMethod, nLine, cMessage, cCode
@@ -914,6 +1001,7 @@ Class[END RESERVED1]
91410011[END RESERVED2]
9151002[START RESERVED3]
9161003*clearqueue Remove all pending commands from queue.
1004+ *displayerrors Default error handler displays list of errors from workers.
9171005*handleerror Global Error Handler.
9181006*processqueue Process command queue.
9191007*queuecommand Add command to queue.
@@ -930,6 +1018,7 @@ nbusyworkers Number of workers currently processing commands.
9301018ncpucount Number of logical processors on machine.
9311019nprocessing Number of times ProcessQueue has been called.
9321020nworkercount Number of workers. Defaults to CPU count.
1021+ oerrorlist Reference to error list form.
9331022workers Workers collection.
9341023[END RESERVED3]
9351024[START RESERVED6]
@@ -949,7 +1038,7 @@ Pixels[END RESERVED6]
9491038[START PROPERTIES]
9501039Enabled = .F.
9511040Height = 23
952- Interval = 10
1041+ Interval = 1
9531042Name = "tmrcommand"
9541043Width = 23
9551044_memberdata = <VFPData><memberdata name="processcommand" display="ProcessCommand"/><memberdata name="lprocessed" display="lProcessed"/><memberdata name="omanager" display="oManager"/></VFPData>
@@ -966,7 +1055,7 @@ Local loManager
9661055
9671056This.Enabled = .f.
9681057Doevents
969- * Timer can fire more than once before it is enabled .
1058+ * Timer can fire more than once before it is disabled .
9701059* Doevents usually prevents this from happening, but this code ensures it.
9711060If This.lProcessed
9721061 Return
@@ -1070,11 +1159,13 @@ Debugout Time(0), Program(), cCriticalSectionName
10701159
10711160* Find and release mutex
10721161lnRow = Ascan(This._CriticalSections, cCriticalSectionName, 1, 0, 1, 8)
1073- lnhMutex = This._CriticalSections[lnRow,2]
1074- ReleaseMutex(lnhMutex)
1162+ If lnRow <> 0
1163+ lnhMutex = This._CriticalSections[lnRow,2]
1164+ ReleaseMutex(lnhMutex)
10751165
1076- * Remove from array
1077- Adel(This._CriticalSections, lnRow)
1166+ * Remove from array
1167+ Adel(This._CriticalSections, lnRow)
1168+ EndIf
10781169ENDPROC
10791170PROCEDURE isworker
10801171* Returns .T. if currently running in Worker process.
@@ -1090,21 +1181,23 @@ cAlias = Evl(cAlias, Alias())
10901181cDirectory = Evl(cDirectory, Sys(2023))
10911182
10921183Do while .t.
1093- lcTempName = Sys(2015)
1094- * Use critical section to make sure multiple workers don't try to use the same filename
1095- This.StartCriticalSection("ReturnCursor " + lcTempName )
1184+ * Sys(2015) may actually return the same value in separate processes
1185+ * Add ThreadID to the name to make sure it is unique across all workers
1186+ lcTempName = Sys(2015) + "_ " + Transform(_VFP.ThreadId )
10961187 lcTempFile = Addbs(cDirectory) + lcTempName
10971188 If !File(lcTempFile + ".dbf") and !File(lcTempFile + ".dbc")
10981189 Exit
10991190 EndIf
1100- This.EndCriticalSection("ReturnCursor" + lcTempName)
11011191EndDo
11021192
11031193* Create database to support long field names
11041194lcDBC = Dbc()
1195+ If !DBused(lcDBC)
1196+ * Full path may not work if DBC is compiled into EXE/APP
1197+ lcDBC = JustStem(JustFname(lcDBC))
1198+ EndIf
11051199lnCurrentArea = Select()
11061200Create Database (lcTempFile)
1107- This.EndCriticalSection("ReturnCursor" + lcTempName)
11081201
11091202* Copy cursor to temp table
11101203Select (cAlias)
@@ -1295,7 +1388,10 @@ EndIf
12951388
12961389* In Windows XP and earlier, main process can lose focus when
12971390* instantiating COM EXE. Make sure we keep it.
1298- If GetForegroundWindow() <> lhWndForeground
1391+ * This issue apparently only affects IDE, and can cause wrong window
1392+ * to get focus at runtime if workers started when main VFP window is not visible.
1393+ * So, only applying to IDE. May revisit if issue presents itself at runtime or other scenarios.
1394+ If _VFP.StartMode = 0 and GetForegroundWindow() <> lhWndForeground
12991395 DECLARE INTEGER SetForegroundWindow IN user32 INTEGER hwnd
13001396 SetForegroundWindow(lhWndForeground)
13011397EndIf
0 commit comments