I guess I will post the code of my thread func, given the responses I'm getting :)
And the question I'm trying to have answered: Would the garbage collector ever initiate on this thread if I start it with CreateThread()? I don't want it to.
STRUCT HeartBeatMonitor_ThreadData
MEMBER hWnd AS PTR
MEMBER hEventSource AS PTR
MEMBER pszEventSource AS PSZ
MEMBER RootDirectory AS PSZ
MEMBER sTimeStart AS _winSYSTEMTIME
MEMBER sTimeEnd AS _winSYSTEMTIME
FUNCTION HeartbeatMonitor(sHeartBeatMonitor_ThreadData AS HeartBeatMonitor_ThreadData) AS DWORD PASCAL
// Do not declare any locals here. Garbage collector is not thread safe.
// Also must not call any functions including VO builtins that might allocate memory.
DO WHILE TRUE
IF sHeartBeatMonitor_ThreadData.hWnd != NULL_PTR
IF IsHungAppWindow(sHeartBeatMonitor_ThreadData.hWnd)
IF sHeartBeatMonitor_ThreadData.sTimeStart == NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeStart := MemAlloc(_SizeOf(_winSYSTEMTIME))
GetLocalTime(sHeartBeatMonitor_ThreadData.sTimeStart)
sHeartBeatMonitor_ThreadData.hEventSource := RegisterEventSource(NULL_PSZ, sHeartBeatMonitor_ThreadData.pszEventSource)
ReportEvent(sHeartBeatMonitor_ThreadData.hEventSource, EVENTLOG_WARNING_TYPE, 0, MSG_APPLICATION_HANG, NULL_PTR, 1, 0, @sHeartBeatMonitor_ThreadData.RootDirectory, NULL_PTR)
DeregisterEventSource(sHeartBeatMonitor_ThreadData.hEventSource)
sHeartBeatMonitor_ThreadData.hEventSource := NULL_PTR
END IF
ELSE
IF sHeartBeatMonitor_ThreadData.sTimeStart != NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeEnd := MemAlloc(_SizeOf(_winSYSTEMTIME))
GetLocalTime(sHeartBeatMonitor_ThreadData.sTimeEnd)
sHeartBeatMonitor_ThreadData.hEventSource := RegisterEventSource(NULL_PSZ, sHeartBeatMonitor_ThreadData.pszEventSource)
ReportEvent(sHeartBeatMonitor_ThreadData.hEventSource, EVENTLOG_INFORMATION_TYPE, 0, MSG_APPLICATION_RESUME, NULL_PTR, 1, 0, @sHeartBeatMonitor_ThreadData.RootDirectory, NULL_PTR)
DeregisterEventSource(sHeartBeatMonitor_ThreadData.hEventSource)
sHeartBeatMonitor_ThreadData.hEventSource := NULL_PTR
MemFree(sHeartBeatMonitor_ThreadData.sTimeStart)
MemFree(sHeartBeatMonitor_ThreadData.sTimeEnd)
sHeartBeatMonitor_ThreadData.sTimeStart := NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeEnd := NULL_PTR
END IF
END IF
END IF
Sleep(1000)
END DO
RETURN 0
This function runs on the main thread to launch the thread:
FUNCTION HeartbeatMonitorInit(hWnd AS PTR) AS VOID PASCAL
LOCAL sSECURITY_ATTRIBUTES AS _winSECURITY_ATTRIBUTES
LOCAL sHeartBeatMonitor_ThreadData AS HeartBeatMonitor_ThreadData
sSECURITY_ATTRIBUTES := MemAlloc(_SizeOf(_winSECURITY_ATTRIBUTES))
sSECURITY_ATTRIBUTES.nLength := _SizeOf(_winSECURITY_ATTRIBUTES)
sSECURITY_ATTRIBUTES.lpSecurityDescriptor := NULL_PTR
sSECURITY_ATTRIBUTES.bInheritHandle := FALSE
sHeartBeatMonitor_ThreadData := MemAlloc(_SizeOf(HeartBeatMonitor_ThreadData))
sHeartBeatMonitor_ThreadData.hWnd := hWnd
sHeartBeatMonitor_ThreadData.pszEventSource := PszAlloc(String2PSZ("XXXXX"))
sHeartBeatMonitor_ThreadData.RootDirectory := PszAlloc(String2PSZ(gcRootDirectory))
sHeartBeatMonitor_ThreadData.sTimeStart := NULL_PTR
sHeartBeatMonitor_ThreadData.sTimeEnd := NULL_PTR
CreateThread(sSECURITY_ATTRIBUTES, 0, @HeartbeatMonitor(), sHeartBeatMonitor_ThreadData, 0, NULL_PTR)
MemFree(sSECURITY_ATTRIBUTES)
RETURN
Cheers!