Announcement

Collapse
No announcement yet.

Longs vs Dword vs %INVALID_HANDLE_VALUE

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Longs vs Dword vs %INVALID_HANDLE_VALUE

    I believe I found a bug in my code either from my own math or my declaring something incorrectly (like declared as long when it should be declared as Dword)

    One example from Win32Api.inc
    Code:
    ' *****************************************************************************
    ' * NOTE that many variables (and some equates) that were previously declared *
    ' * AS LONG are now correctly defined AS DWORD, which may cause compatibility *
    ' * issues with existing programs. In particular, %INVALID_HANDLE_VALUE is    *
    ' * &HFFFFFFFF??? rather than -1& now.                                        *
    ' *****************************************************************************
    And from my initial tests, sometimes I get a -1 and sometimes I get 4294967295 so I need to do some more testing and change my routines of
    Code:
    IF MyVar then .....
    because I was expecting 0 if it did not exist, not either of the values above or better known as %INVALID_HANDLE_VALUE

    Anyways, somewhere in here I know I have seen a function written that either converts DWORD to Long (or Vice versa), or Signed to Unsigned (or Vice versa) but I can not find it. I have been searching all day for any combination of these key words but found nothing yet.

    Anyone know what these Function(s) are called? or where to find them? or who wrote them? (Gut feeling tells me either MCM or Pierre, but found nothing looking for their posts either)
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

  • #2
    "IF Myvar THEN" works the same regardless if MyVar is a LONG or DWORD. It works as though it were "IF ISTRUE(myvar) THEN..."

    As for comparing PB LONGs with PB DWORDs....

    With PB/DLL 6x or earlier... do nothing special, both IF and SELECT CASE do 32 bit comparisons

    But since you probably are running a version later than 6x (version not shown), this is a MACRO I use (created by Tom Hanlin)
    Code:
    Macro  EQ32 (a, b) =  BITS???(a) = BITS???(b)
    
    ...
      hFile = CreateFile (.......
      IF eq32 (hFile, %INVALID_HANDLE_VALUE) THEN
       '   does not care about casting of either hFile or INVALID_HANDLE VALUE
      .....
    MCM
    Michael Mattias
    Tal Systems Inc. (retired)
    Racine WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      "IF Myvar THEN" works the same regardless if MyVar is a LONG or DWORD. It works as though it were "IF ISTRUE(myvar) THEN..."
      In the "TRUE-est" sense of the word, you are correct. TRUE is defined as non-zero while FALSE is defined as zero. So it is my fault for not accounting for values that are "Non-Zero" but really mean "I can not use it". (Bad habit of being used to "True = 1 and False = 0" and not the true meaning of the values)

      With PB/DLL 6x or earlier... do nothing special, both IF and SELECT CASE do 32 bit comparisons
      Over the years I have code written in PB/DLL 6x and up. And usually have no problem between versions (or if I have a problem, the compiler will not let me compile until I fix the problem).

      This all started from my working on some snippet code to demonstrate an idea, when I found this problem and still not sure how to phrase the question or even supply a test to show what I "THINK" I am seeing. So for a theoretical proof of concept think of it this way.

      Scenario 1:
      1. Older compiler Win32Api.inc declared variables (and some equates) as LONG
      2. My Variables used LONG, so I was good as long as the return value from a function was LONG. If it was DWORD then I was good as long as the value was between 0 and 2,147,483,647 if not then I was in trouble


      Scenario 2:
      1. Newer compiler Win32Api.inc declared variables (and some equates) as DWORD
      2. My Variables used LONG, so I am just asking for it if the returned value is a negative number (DWORD is defined as unsigned integers with a range of 0 to 4,294,967,295)


      Scenario 3:
      1. Either New or Old if I am expecting %INVALID_HANDLE_VALUE (And although not tested, I am sure the compiler will not let me compile the wrong version of "Win32Api.inc")
      2. If My Variable is declared as Long, and the (%INVALID_HANDLE_VALUE = 4294967295 = DWORD) I am in trouble
      3. If My Variable is declared as DWORD, and the (%INVALID_HANDLE_VALUE = -1 = LONG) I am in trouble


      Of course it all makes sense when you think about it...they all break the rules for the intended scenario. Some are more forgiving than others, but rules are rules.

      Kinda like Math, I can add 1cm + 1 mm + 1 inch + 1 yard + 1 kilometer but unless I take into account the "Units" then I get 4...but 4 "WHAT?"

      Anyways the more I think outloud the more I think the snippet I was looking for had something to do with changing Signed values to Unsigned values and back again
      Engineer's Motto: If it aint broke take it apart and fix it

      "If at 1st you don't succeed... call it version 1.0"

      "Half of Programming is coding"....."The other 90% is DEBUGGING"

      "Document my code????" .... "WHYYY??? do you think they call it CODE? "

      Comment


      • #4
        The change from unsigned to signed comparisons for IF/SELECT CASE in 7x was an undocumented "enhancement." SELECT CASE AS LONG added in 7x does 32-bit comparisons.

        It really was a problem only if you decided NOT to change your Win32 header files when you installed 7x. Like I didn't.

        Or if you read the doc and made everything possible a LONG integer for efficiency, then found that some of the stuff in Win32API.INC was changed to DWORD and the comparisons were now signed. Like I did.

        But anyone who started with 7x and that set of WinAPI headers would never know the difference.. except when trying to use code from Source Code Forum posted pre-7X.

        Heck, I still have problems using code posted SINCE 7x, since some of my WinAPI header files are still originals with the fixes I made. (The WinAPI headers are now stable and error-free. 'Twas not always thus). (Big time).

        Essentially PowerBASIC Inc discriminates against us old farts by making us change our ways or do something extra whilst the newbies just 'plug and play.'

        MCM
        Michael Mattias
        Tal Systems Inc. (retired)
        Racine WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Originally posted by Cliff Nichols View Post
          Anyways, somewhere in here I know I have seen a function written that either converts DWORD to Long (or Vice versa), or Signed to Unsigned (or Vice versa) but I can not find it. I have been searching all day for any combination of these key words but found nothing yet.

          Anyone know what these Function(s) are called? or where to find them? or who wrote them? (Gut feeling tells me either MCM or Pierre, but found nothing looking for their posts either)
          From the Help file:
          <H1>CBYT, CCUR, CCUX, CDBL, CDWD, CEXT, CINT, CLNG, CQUD, CSNG, and CWRD functions

          These conversion functions are rarely needed as PowerBASIC automatically performs any necessary conversions when executing an assignment statement or passing parameters.
          </H1>
          Regards,
          Bob

          Comment


          • #6
            Interesting Test

            Here is an interesting lil test. I was able to determine why sometimes I got -1 for %INVALID_HANDLE_VALUE and why sometimes it was 4294967295. It was because sometimes I had the variable declared as Long, sometimes as DWORD. (As you can test by commenting and uncommenting those lines in the code below)
            1. If I close a thread that purposely has an invalid thread handle, then yes the program will throw up an exception (like the documentation states) but as an exe, I do not see the exception, and when I close the program, it does remove from the list of running processes, but if I recompile and run again I get the "Destination file in use" error. However the process is not seen by "Windows Task Manager" nor by SysInternals "Process Viewer" (yep I am watching both as I run and close)
            2. The only thing that will truly release whatever memory location that is not letting go, is to reboot the computer


            Anyways as for the demo of Long vs Dword (using PB Win 8.03 Win32Api.inc) you will see if I declare my variable as Long, then invalid handle is -1 and if I declare my variable as DWORD then invalid value = 4294967295

            Code:
            #COMPILE EXE
            #DIM ALL
            
            '------------------------------------------------------------------------------
            '   ** Includes **
            '------------------------------------------------------------------------------
            #IF NOT %DEF(%WINAPI)
                #INCLUDE "WIN32API.INC"
            #ENDIF
            '------------------------------------------------------------------------------
            
            '------------------------------------------------------------------------------
            '   ** Constants **
            '------------------------------------------------------------------------------
            %IDD_DIALOG1 =  101                                                             'Demo Dialog
            %IDC_BUTTON2 = 1002                                                             'Loop with thread
            '------------------------------------------------------------------------------
            
            '------------------------------------------------------------------------------
            '   ** Declarations **
            '------------------------------------------------------------------------------
            DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()                                     'Callback function for Windows Messages
            DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG                    'Create and show the demo
            
            DECLARE FUNCTION ThreadLoopDemo(BYVAL x AS LONG)AS LONG                         'Create Threaded Demo
            DECLARE FUNCTION LoopDemo()AS LONG                                              'Function called both by Thread and without a thread
            DECLARE FUNCTION CreateThreadLoop()AS LONG                                      'Create Thread
            DECLARE FUNCTION DestroyThreadLoop()AS LONG                                     'Destroy Thread and Wait till Thread is Dead
            '------------------------------------------------------------------------------
            
            
            '------------------------------------------------------------------------------
            '   ** Globals **
            '------------------------------------------------------------------------------
            GLOBAL hDlg  AS DWORD                                                           'Dialog
            GLOBAL EscapeLoop AS LONG                                                       'Flag to escape loop
            GLOBAL ThreadLoop AS LONG                                                       'Thread to be closed if open
            'GLOBAL ThreadLoop AS DWORD                                                       'Thread to be closed if open
            GLOBAL FakeThreadLoop AS LONG                                                   'Bogus number for showing demo
            '------------------------------------------------------------------------------
            
            '------------------------------------------------------------------------------
            '   ** Main Application Entry Point **
            '------------------------------------------------------------------------------
            FUNCTION PBMAIN()
                 ShowDIALOG1 %HWND_DESKTOP                                                  'Start Callback function to show dialog
            END FUNCTION
            '------------------------------------------------------------------------------
            
            '------------------------------------------------------------------------------
            '   ** CallBacks **
            '------------------------------------------------------------------------------
            CALLBACK FUNCTION ShowDIALOG1Proc()
                 SELECT CASE AS LONG CBMSG                                                  'Check what message was sent
                      CASE %WM_COMMAND                                                      'Process control notifications
                           SELECT CASE AS LONG CBCTL
                                CASE %IDC_BUTTON2                                           'Loop with thread
                                     IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN         '<--- Not sure why CBCTLMSG = 1 is used?
                                          DestroyThreadLoop                                 'Destroy Thread if it already exists
                                          EscapeLoop = %FALSE                               'Set Flag to false in case was already set to true
                                          CreateThreadLoop                                  'Create Thread (returns Immediately) which then starts the loop
                                     END IF
                           END SELECT
                      CASE %WM_CLOSE
                           DestroyThreadLoop                                                'Destroy Thread if it already exists
                           EXIT FUNCTION
                 END SELECT
            END FUNCTION
            '------------------------------------------------------------------------------
            
            '------------------------------------------------------------------------------
            '   ** Dialogs **
            '------------------------------------------------------------------------------
            FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                 LOCAL lRslt AS LONG
                 DIALOG NEW hParent, "Blocking Thread Test", 70, 70, 200, 79, %WS_POPUP OR _          'PbForms create dialog with common properties
                                     %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                                     %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
                                     %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
                                     %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
                                     %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                 CONTROL ADD BUTTON, hDlg, %IDC_BUTTON2, "Global Threaded Flag", 95, 15, 100, 20
                 DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt                                'Show Modal (no message pump needed)
                 FUNCTION = lRslt
            END FUNCTION
            '------------------------------------------------------------------------------
            FUNCTION ThreadLoopDemo(BYVAL x AS LONG)AS LONG                                           'Thread Wrapper Function
                 LoopDemo                                                                             'Call Loop Demo within this thread
            END FUNCTION
            
            FUNCTION LoopDemo()AS LONG                                                                'Demo Function (will not die until flag is seen to escape loop
            ''*************************************************************************************************
            ''*** Left in just for Demo purposes although it does nothing while commented
            ''*************************************************************************************************
            '     DO
            '          IF EscapeLoop = %True THEN EXIT DO                                              'Check if Flag is set to escape?
            '     LOOP
            'MSGBOX FUNCNAME$ + $CR + "Escaped the Loop with EscapeLoop = " + STR$(EscapeLoop)         'For Display purposes of demo
            END FUNCTION
            
            FUNCTION CreateThreadLoop()AS LONG                                                        'Create a thread so rest of program is not stalled waiting for a function to finish
                 LOCAL lResult AS LONG
                 LOCAL ErrorBuff AS ASCIIZ * %MAX_PATH
                 NewThread = FREEFILE
                 SELECT CASE ThreadLoop
                      CASE %INVALID_HANDLE_VALUE, 4294967295, -1                 '%INVALID_HANDLE_VALUE used to be -1 and re-used as (&HFFFFFFFF??? = 4,294,967,295)
                           THREAD CREATE ThreadLoopDemo(1) TO ThreadLoop         '<--- Thread handle is invalid so its ok to create a new one
                      CASE 0
                           THREAD CREATE ThreadLoopDemo(1) TO ThreadLoop         '<--- Thread handle is invalid so its ok to create a new one
                      CASE ELSE
                           'Do nothing because a thread handle already exists
                 END SELECT
                 lResult = GetLastError()           'Check for the error
                 FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL  'Format the message
            MSGBOX FUNCNAME$ + $CR + "Thread Value = " + STR$(ThreadLoop) + $CR + ErrorBuff
                 FUNCTION = ThreadLoop                                                                '<--- Return the value of the Thread Handle (0 if Thread failed to start)
            END FUNCTION
            
            FUNCTION DestroyThreadLoop()AS LONG                                                       'Destroy thread so not inadvertantly left running when parent process closes
                 LOCAL TempThread AS LONG
                 LOCAL lResult AS LONG
                 LOCAL ErrorBuff AS ASCIIZ * %MAX_PATH
                 TempThread = ThreadLoop
                 SELECT CASE ThreadLoop
                      CASE %INVALID_HANDLE_VALUE, 4294967295, -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 ThreadLoop TO ThreadLoop
                           SELECT CASE ThreadLoop
                                CASE %INVALID_HANDLE_VALUE, 4294967295, -1                 '%INVALID_HANDLE_VALUE used to be -1 and re-used as (&HFFFFFFFF??? = 4,294,967,295)
                                     'Do NOTHING because Thread is closed, and handle is invalid
                                CASE 0
                                    'Do NOTHING because already closed
                                CASE ELSE
                                     WaitForSingleObject ThreadLoop, %INFINITE                        'Thread closed but handle not invalidated, so wait till thread done
                           END SELECT
                 END SELECT
                 lResult = GetLastError()           'Check for the error
                 FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL  'Format the message
            MSGBOX "%INVALID_HANDLE_VALUE DWORD= " + STR$(%INVALID_HANDLE_VALUE) + $CR + $CR _
                      + "DWORD should Read as 4,294,967,295" + $TAB + $TAB + "LONG should Read as -1" + $CR + $CR _
                      + "ThreadLoop before close = " + STR$(TempThread) + $TAB + $TAB + "ThreadLoop after close = " + STR$(ThreadLoop)
                 FUNCTION = ThreadLoop
            END FUNCTION
            Engineer's Motto: If it aint broke take it apart and fix it

            "If at 1st you don't succeed... call it version 1.0"

            "Half of Programming is coding"....."The other 90% is DEBUGGING"

            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

            Comment


            • #7
              you will see if I declare my variable as Long, then invalid handle is -1 and if I declare my variable as DWORD then invalid value = 4294967295
              Hell, if you were to declare it as a STRING the value would be REPEAT$(CHR$(255), 4)

              Actually the value never changes at ALL. What you are reporting is how you are currently looking at the same four bytes returned by the WinAPI.

              MCM
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                MCM....you will LOVE this one then for ammo about Globals vs Locals

                I get the concept of "Its not the data, its how you are looking at it" but can anyone then explain why a global and a local would come up different values? (see below)

                Code:
                #COMPILE EXE
                #DIM ALL
                #INCLUDE "WIN32API.INC"
                '***************************************************
                '*** %INVALID_HANDLE_VALUE as Dword = 4294967295 ***
                '*** %INVALID_HANDLE_VALUE as Long = -1          ***
                '***************************************************
                GLOBAL gInvalidHandleDword AS DWORD                         '<--- Correct value returns
                GLOBAL gInvalidHandleLong AS LONG                           '<--- Incorrect value returns
                
                FUNCTION PBMAIN () AS LONG
                    LOCAL lInvalidHandleDword AS DWORD                      '<--- Correct value returns
                    LOCAL lInvalidHandleLong AS LONG                        '<--- Correct value returns
                '*** Plug in LONG definition of %INVALID_HANDLE_VALUE into DWORD variables
                    gInvalidHandleDword = -1
                    lInvalidHandleDword = -1
                '*** Plug in DWORD definition of %INVALID_HANDLE_VALUE into LONG variables
                    gInvalidHandleLong = 4294967295
                    lInvalidHandleLong = 4294967295
                MSGBOX FUNCNAME$ + $CR + $CR _
                                    + "Global Invalid Dword with -1 = " + STR$(gInvalidHandleDword) + $CR _
                                    + "Local Invalid Dword with -1 = " + STR$(lInvalidHandleDword) + $CR + $CR _
                                    + "Global Invalid Long with 4294967295 = " + STR$(gInvalidHandleLong) + $CR _
                                    + "Local Invalid Long with 4294967295 = " + STR$(lInvalidHandleLong)
                END FUNCTION
                I get the idea that plugging in the wrong value is returning the lowest possible number for a LONG, but what I do not get is why wouldn't the local variable do the same?
                Last edited by Cliff Nichols; 7 Dec 2007, 12:27 PM.
                Engineer's Motto: If it aint broke take it apart and fix it

                "If at 1st you don't succeed... call it version 1.0"

                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                Comment


                • #9
                  >MCM....you will LOVE this one then for ammo about Globals vs Locals

                  Actually, I will love it for ammo re my request for overflow checking.

                  Sheesh, Cliff, don't tell me you didn't recognize you have made the "rookiest" of rookie mistakes: making assignments which overflow the destination variables.

                  (You can't fit "minus anything" into a DWORD nor can you fit 4,294,967,295 into a LONG).

                  Not to mention not explicitly casting your inline numeric literals. Back to...
                  Code:
                  10 PRINT "HELLO, WORLD"
                  20 END
                  30 ^C
                  Ready> RUN
                  ... for you!

                  MCM
                  Michael Mattias
                  Tal Systems Inc. (retired)
                  Racine WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    MCM it gets even funnier

                    Just for you, try running my example in the debugger. Both animated and Run until break will give me "-2147483648" for both the gInvalidHandleLong and the lInvalidHandleLong

                    However just "Compile and Run" I get "-2147483648" for gInvalidHandleLong but I get "-1" for the lInvalidHandleLong

                    Sheesh, Cliff, don't tell me you didn't recognize you have made the "rookiest" of rookie mistakes: making assignments which overflow the destination variables.
                    nope....was just proving a point. I had "ASSUMED" that somehow the compiler was handling things behind the scenes that if I plugged a Negative number into a DWORD (which breaks the rules), or a value larger than a Long could handle (again breaks the rules) because I get no error.

                    And on TOP of that, not only do I get answers...I (For lack of a better word) "Almost" get the right answer.

                    If you consider "Almost" a working Overflow error.

                    Anyways now you see one of my problems that I did not even notice until looking for something in the Win32Api.inc and noticed that note.

                    Give the debug a run and you will see how things get worse, if you do not know you are plugging illegal values in.
                    Engineer's Motto: If it aint broke take it apart and fix it

                    "If at 1st you don't succeed... call it version 1.0"

                    "Half of Programming is coding"....."The other 90% is DEBUGGING"

                    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                    Comment


                    • #11
                      >see how things get worse, if you do not know you are plugging illegal values in

                      Duh, that's why I have submitted a NSF for an "#OVERFLOW ON" option!!!!!

                      Sheesh.
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        ok calm down MCM.... I wasn't trying to start a holy-war with this one. Just trying to figure things out....and the more I figured out, the more I tried to show by "Worst Case Scenario" and how even if it was "allowed" for me to use invalid values, that Windows did not do some sort of GPF. At least then I would have maybe noticed sooner that code I did in the past and through the future may have been wrong in the 1st place.

                        In this case I have to check all my code and calculations and determine if I used a Long when I should have used a Dword, or vice-versa?

                        I am sure the reason I never caught this mistake before is, lets face it, how often do you come across a variable meant to be a whole value that did not come up somewhere between 0 and 2,147,483,647


                        Not to get confused....what is a NSF? (I know it has to do with requesting an option or a fix, but dunno what NSF stands for?)

                        Anyways, I now know what started out as what I thought was 1 problem, was really 2 separate problems that "cropped up" at the same time. I will go back and clean up my mistakes of Long vs Dword problem.

                        I know I have another problem (well not problem because I know why it crops up, and maybe a solution) that will remain once the code is cleaned up. But wonder if best to post here? or a new question so as not to add confusion and someone still think its a Long vs Dword debate?
                        Engineer's Motto: If it aint broke take it apart and fix it

                        "If at 1st you don't succeed... call it version 1.0"

                        "Half of Programming is coding"....."The other 90% is DEBUGGING"

                        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                        Comment


                        • #13
                          My bad, should be "NFS" not "NSF," as in New Feature Suggestion.

                          I must have typed that incorrectly because I was talking with a guy in Louisville earlier today and the subject of "NSF" as in (N)ational (S)tandard (F)ormat came up.

                          MCM
                          Michael Mattias
                          Tal Systems Inc. (retired)
                          Racine WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment

                          Working...
                          X