Code:
'*** Compiler Directives #COMPILE EXE #DIM ALL #INCLUDE "Win32Api.inc" '*** Equates '*** Although not GLOBALS they are known to all functions/subs involved that need them %UNKNOWN = -1 '*** Declares '*** Most code shows without, I am more a believer of "THOU SHALT DECLARE, WHAT THOU SHALT USE" DECLARE FUNCTION PBMAIN () AS LONG 'Main Program DECLARE FUNCTION VerifyIfDevice() AS LONG 'Used to verify if the device attached is the one you are looking for DECLARE FUNCTION OpenListenThread ALIAS "OpenListenThread"() AS LONG 'Thread to "Listen" for an event on the serial port DECLARE FUNCTION CloseListenThread ALIAS "CloseListenThread"() AS LONG 'Close the thread before exiting to avoid crashes DECLARE FUNCTION ReceiveData(BYVAL HwndTerminal AS DWORD) AS LONG 'Does the work of checking if some event (aka character is ready to be read) '*** Global Replacement functions '*** Use replacement functions to store variables so correct value is valid between threads '*** Return value is DWORD to indicate if the function had an error (%TRUE = NON-ZERO, or %FALSE = ZERO, to work with most API Functions) DECLARE FUNCTION SetGetBuffer(Buffer AS STRING, ReturnBuffer AS STRING, ResetBuffer AS LONG) AS DWORD 'Replacement for global variable DECLARE FUNCTION SetGetDeviceFound(DeviceFound AS LONG, ReturnDeviceFound AS LONG, ResetDeviceFound AS LONG) AS DWORD 'Replacement for global variable DECLARE FUNCTION SetGetHwndThread(HwndThread AS LONG, ReturnHwndThread AS LONG, ResetHwndThread AS LONG) AS DWORD 'Replacement for global variable '************************************************************************************************************** '*** Globals '*** Globals replaced by functions to avoid invalid values, and speed up processes 'GLOBAL Buffer AS STRING 'String for whatever the device has sent 'GLOBAL DeviceFound AS LONG 'Flag for if device found 'GLOBAL ThreadNumber AS LONG 'Thread Number (No longer needed whatsoever) 'GLOBAL HwndThread AS LONG 'Handle to the thread 'GLOBAL HwndThreadDone AS LONG 'Handle to if the thread is done running '************************************************************************************************************** FUNCTION PBMAIN () AS LONG LOCAL Msg AS STRING 'Local variable for MSGBOX demonstration LOCAL Buffer AS STRING '<--- Was a Global, now a function (being local, is more understandable to read in larger projects) LOCAL DeviceFoundBefore AS LONG '<--- Was a Global, now a function (being local, is more understandable to read in larger projects) LOCAL DeviceFoundAfter AS LONG '<--- Was a Global, now a function (being local, is more understandable to read in larger projects) '*** Demo variables kept local LOCAL PurposeSetGetBuffer AS STRING 'For Demo Purpose LOCAL PurposeError AS LONG 'For Demo Purpose (If I had left error handling in) OpenListenThread 'Create a listening thread ' SLEEP 100 '<--- Remember Sleep does not mean (wait 100ms, it means "Wait 100ms and give another thread a chance, if timeslice is returned and time is up, then continue...if not, let another slice have it) SLEEP 1 '<--- Remember Sleep does not mean (wait Xms, it means "Wait Xms and give another thread a chance, if timeslice is returned and time is up, then continue...if not, let another slice have it) '*** For Demo Purposees SetGetDeviceFound(0, DeviceFoundBefore, %UNKNOWN) 'Call the function just to see if the variable is set ' DeviceFound = VerifyIfDevice 'If flag is set, then I found my device '<---Note to self, should this function not work if I have not declared it yet? CloseListenThread 'Never leave a thread open SetGetDeviceFound(%FALSE, DeviceFoundAfter, %TRUE) 'Release Device found SetGetDeviceFound(0, DeviceFoundAfter, %UNKNOWN) 'Call the function just to see if the variable is set '*** Demonstrate SetGetBuffer("", Buffer, %UNKNOWN) 'Check if anything in the buffer '*** Build the MSGBOX string Msg = Msg + FUNCNAME$ + $CR 'Function Name Msg = Msg + "Buffer = " + Buffer + $CR 'What would be in the buffer Msg = Msg + "Error in DeviceFound = " + STR$(DeviceFoundBefore) 'If error handling then what would be in the error Msg = Msg + $CR Msg = Msg + "Device Handle before release = " + STR$(DeviceFoundBefore) + $CR 'If DeviceFound (even simulated) Msg = Msg + "Device Handle after release = " + STR$(DeviceFoundAfter) + $CR 'If DeviceFound (even simulated) '*** Show the messagebox MSGBOX Msg END FUNCTION FUNCTION VerifyIfDevice() AS LONG LOCAL Buffer AS STRING '<--- Was a Global, now a function (being local, is more understandable to read in larger projects) LOCAL DeviceFound AS LONG '<--- Was a Global, now a function (being local, is more understandable to read in larger projects) SetGetBuffer("", Buffer, %UNKNOWN) 'Call the function just to see if the variable is set SELECT CASE RIGHT$(Buffer,1) CASE "R", "J" 'Purposely set the flag SetGetDeviceFound(%TRUE, DeviceFound, %TRUE) ' DeviceFound = %True CASE "B", "b" 'Purposely set the flag CASE "^" 'Purposely set the flag CASE ELSE 'Purposely set the flag END SELECT ' function = %TRUE 'Purposely set the flag for an error if there was an error END FUNCTION FUNCTION OpenListenThread ALIAS "OpenListenThread"() AS LONG STATIC ThreadNumber AS LONG LOCAL HwndThread AS LONG IF ThreadNumber = 0 THEN ThreadNumber = ThreadNumber + 1 '*** Although Hardcoded, it demonstrates creating a thread SetGetDeviceFound(ThreadNumber, HwndThread, %TRUE) 'Call the function and set it THREAD CREATE ReceiveData(ThreadNumber) TO HwndThread 'Create a "listen" thread to monitor input from device FUNCTION = %True END FUNCTION FUNCTION CloseListenThread ALIAS "CloseListenThread"() AS LONG STATIC ThreadNumber AS LONG LOCAL HwndThread AS LONG SetGetHwndThread(0, HwndThread, %UNKNOWN) 'Call the function to get the HwndThread IF ThreadNumber <> 0 THEN ThreadNumber = ThreadNumber - 1 SetGetDeviceFound(0, ThreadNumber, %UNKNOWN) 'Call the function just to see if the variable is set SELECT CASE HwndThread CASE %INVALID_HANDLE_VALUE, -1 '%INVALID_HANDLE_VALUE used to be -1 and re-used as (&HFFFFFFFF??? = 4,294,967,295) 'Do NOTHING because closing an invalid handle raises an exception CASE 0 'Do NOTHING because already closed CASE ELSE THREAD CLOSE HwndThread TO HwndThread SELECT CASE HwndThread CASE %INVALID_HANDLE_VALUE, -1 '%INVALID_HANDLE_VALUE used to be -1 and re-used as (&HFFFFFFFF??? = 4,294,967,295) 'Do NOTHING because closing an invalid handle raises an exception CASE 0 'Do NOTHING because already closed CASE ELSE IF HwndThread THEN WaitForSingleObject HwndThread, %INFINITE 'Wait for it to finish, or risk GPF END SELECT END SELECT IF HwndThread THEN HwndThread = 0 SetGetHwndThread(HwndThread, HwndThread, %True) 'Call the function to reset the HwndThread FUNCTION = HwndThread END FUNCTION FUNCTION ReceiveData(BYVAL HwndTerminal AS DWORD) AS LONG LOCAL TempBuffer AS STRING 'Copy of what would be in the "GLOBAL" buffer ' Buffer = "R" 'Simulate reply SetGetBuffer("R", TempBuffer, %True) 'Simulate reply END FUNCTION FUNCTION SetGetBuffer(Buffer AS STRING, ReturnBuffer AS STRING, ResetBuffer AS LONG) AS DWORD STATIC TempBuffer AS STRING 'Copy of what would be in the "GLOBAL" buffer SELECT CASE ResetBuffer 'Depending on Reset, either Set, or check the current value CASE %FALSE, %UNKNOWN ReturnBuffer = TempBuffer CASE = %TRUE TempBuffer = Buffer Buffer = TempBuffer END SELECT END FUNCTION FUNCTION SetGetDeviceFound(DeviceFound AS LONG, ReturnDeviceFound AS LONG, ResetDeviceFound AS LONG) AS DWORD STATIC TempDeviceFound AS LONG 'Copy of what would be in the "GLOBAL" buffer SELECT CASE ResetDeviceFound 'Depending on Reset, either Set, or check the current value CASE %FALSE, %UNKNOWN ReturnDeviceFound = TempDeviceFound CASE = %TRUE TempDeviceFound = DeviceFound DeviceFound = TempDeviceFound END SELECT END FUNCTION FUNCTION SetGetHwndThread (HwndThread AS LONG, ReturnHwndThread AS LONG, ResetHwndThread AS LONG) AS DWORD STATIC TempHwndThread AS LONG 'Copy of what would be in the "GLOBAL" buffer SELECT CASE ResetHwndThread 'Depending on Reset, either Set, or check the current value CASE %FALSE, %UNKNOWN ReturnHwndThread = TempHwndThread CASE = %TRUE TempHwndThread = HwndThread HwndThread = TempHwndThread END SELECT END FUNCTION
Leave a comment: