Announcement

Collapse
No announcement yet.

UDT Scope & Invalid User Buffer

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

  • UDT Scope & Invalid User Buffer

    I started with one problem but in the course of creating a test version I found two more.
    The more the merrier! Anyway, the two problems revolve around getting errors that
    depend upon what the scope of some UDT declares are, LOCAL or STATIC.

    Problem 1) A UDT defined LOCAL doesn't work with the SIZEOF function, returning zero.
    Problem 2) In another case, a UDT defined STATIC will cause a GPF in a function call.

    Any advice most welcome!

    ---
    The code below illustrates the Problems, which are marked by '*******' comments.
    This should compile on most any Windows OS that has USB support (maybe not Win95 OSR2).
    Code:
    ' HID.BAS
    ' Program for testing the HID/USB drivers
    '
    ' Requires that a current SETUPAPI.DLL and HID.DLL be present (should be on systems with
    ' USB support)
    ' 
    ' This program just enumerates the HID (Human Interface Device) interfaces 
    ' and shows their Symbolic Link name
    '
    #Compile Exe "hid.exe"
    
    #Dim All
    
    #Register None
    
    #Include "win32api.inc"
    
    ' GUID Data Type
    Type GUID
       Data1                As Long
       Data2                As Integer
       Data3                As Integer
       Data4(7)             As Byte
    End Type
    
    Type SP_DEVICE_INTERFACE_DATA
       cbSize                  As Dword
       InterfaceClassGuid      As GUID
       Flags                   As Dword
       Reserved                As Dword
    End Type
    
    Type SP_DEVICE_INTERFACE_DETAIL_DATA
       cbSize                  As Dword
       DevicePath              As Asciiz * 100
    End Type
    
    %DIGCF_PRESENT             = &H00000002
    %DIGCF_DEVICEINTERFACE     = &H00000010
    
    ' Function declares
    Declare Sub HidD_GetHidGuid StdCall Lib "HID.DLL" Alias "HidD_GetHidGuid" _
       ( _
       HidGuid                             As GUID _
       )
    
    Declare Function SetupDiGetClassDevs Cdecl Lib "Setupapi.dll" Alias "SetupDiGetClassDevsA" _
       ( _
       ByRef ClassGuid                     As GUID, _
       ByRef Enumerator                    As Dword, _
       ByVal hwndParent                    As Long, _
       ByVal Flags                         As Dword _
       ) As Dword
    
    Declare Function SetupDiEnumDeviceInterfaces Cdecl Lib "Setupapi.dll" Alias "SetupDiEnumDeviceInterfaces" _
       ( _
       ByVal DeviceInfoSet                 As Dword, _
       ByVal DeviceInfoData                As Dword, _
       ByRef InterfaceClassGuid            As GUID, _
       ByVal MemberIndex                   As Dword, _
       ByRef DeviceInterfaceData           As SP_DEVICE_INTERFACE_DATA _
       ) As Long
    
    Declare Function SetupDiGetDeviceInterfaceDetail Cdecl Lib "Setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailA" _
       ( _
       ByVal DeviceInfoSet                 As Dword, _
       ByRef DeviceInterfaceData           As SP_DEVICE_INTERFACE_DATA, _
       ByRef DeviceInterfaceDetailData     As SP_DEVICE_INTERFACE_DETAIL_DATA, _
       ByVal DeviceInterfaceDetailDataSize As Dword, _
       ByRef RequiredSize                  As Dword, _
       ByVal DeviceInfoData                As Dword _
       ) As Long
    
    
    Declare Function SetupDiDestroyDeviceInfoList Cdecl Lib "Setupapi.dll" Alias "SetupDiDestroyDeviceInfoList" _
       ( _
       ByVal DeviceInfoSet                 As Dword _
       ) As Long
    
    
    ' ***********************************************************************
    ' Compiler directives: Only use one option at a time
    %TEST_NORMAL			= 1&
    '%TEST_SIZEOF 			= 1&
    '%TEST_GPF   			= 1&
    ' ***********************************************************************
    
    
    Function PbMain
    '
    ' Program start
    '
       Local hDevInfo    As Dword Ptr
       Local dwReqLen    As Dword
       Local dwInstance  As Dword
       Local tHidGuid    As GUID
       
    ' ***********************************************************************
    #If %Def(%TEST_NORMAL)
    	Static tIfcData   As SP_DEVICE_INTERFACE_DATA
    	Local tIfcDetail  As SP_DEVICE_INTERFACE_DETAIL_DATA
    
    #ElseIf %Def(%TEST_SIZEOF)
    	Local tIfcData   As SP_DEVICE_INTERFACE_DATA
    	Static tIfcDetail  As SP_DEVICE_INTERFACE_DETAIL_DATA
    
    #ElseIf %Def(%TEST_GPF)
    	Static tIfcData   As SP_DEVICE_INTERFACE_DATA
    	Static tIfcDetail  As SP_DEVICE_INTERFACE_DETAIL_DATA
    #EndIf
    ' ***********************************************************************
    
       ' Get the GUID of the HID interface
       HidD_GetHidGuid tHidGuid
    
       Do
    
          MsgBox "SetupDiGetClassDevs next"
          ' Get handle to relevant device information set
          hDevInfo = SetupDiGetClassDevs(tHidGuid, %NULL, %NULL, %DIGCF_PRESENT Or %DIGCF_DEVICEINTERFACE)
          If hDevInfo = %INVALID_HANDLE_VALUE Then
             MsgBox "No HDEVINFO available for this GUID"
             Exit Do
          End If
    
          ' Get interface data for the requested instance
          tIfcData.cbSize = SizeOf(tIfcData)
    
          ' ***********************************************************************
          ' Problem 1:
          ' When %TEST_SIZEOF is true, the SIZEOF function returns 0, not 28
          ' ***********************************************************************
          
          MsgBox "Size of tIfcData (should be 28):" & Str$(tIfcData.cbSize)
          MsgBox "SetupDiEnumDeviceInterfaces next"
       
          ' ***********************************************************************
          ' Problem 2:
          ' When %TEST_GPF is true, this function call causes a GPF
          ' ***********************************************************************
          If IsFalse SetupDiEnumDeviceInterfaces(hDevInfo, %NULL, tHidGuid, dwInstance, tIfcData) Then
    
             MsgBox "SetupDiEnumDeviceInterfaces failed"
             SetupDiDestroyDeviceInfoList hDevInfo
             Exit Do
    
          End If
    
          ' Get the size of symbolic link name
          MsgBox "SetupDiGetDeviceInterfaceDetail - Get Buffer Size next"
       
          SetupDiGetDeviceInterfaceDetail hDevInfo, tIfcData, ByVal %NULL, 0???, dwReqLen, %NULL
    
          If dwReqLen = 0 Then
    
             MsgBox "SetupDiGetDeviceInterfaceDetail - Get Buffer Size failed"
             SetupDiDestroyDeviceInfoList hDevInfo
             Exit Do
    
          End If
    
          MsgBox "Size of buffer (should be 86) =" & Str$(dwReqLen)
          
          ' Set the size param to 5 - DWORD size plus 1
          tIfcDetail.cbSize = 5
    
          ' Get symbolic link name
          MsgBox "SetupDiGetDeviceInterfaceDetail - Get Symbolic Link Name next"
          If IsFalse SetupDiGetDeviceInterfaceDetail(hDevInfo, tIfcData, tIfcDetail, dwReqLen, ByVal %NULL, %NULL) Then
    
             MsgBox "SetupDiGetDeviceInterfaceDetail - Get Symbolic Link Name failed"
    
             SetupDiDestroyDeviceInfoList hDevInfo
             Exit Do
    
          End If
    
          MsgBox "Symbolic link is " & tIfcDetail.DevicePath
    
          Incr dwInstance
    
       Loop
    
    End Function

    ------------------
    Mark Newman



    [This message has been edited by Mark Newman (edited April 10, 2001).]
    Mark Newman

  • #2
    Mark,

    I use SIZEOF with LOCAL udt's all the time. It works fine for
    me...



    ------------------
    Bernard Ertl
    Bernard Ertl
    InterPlan Systems

    Comment


    • #3
      I suspect you're still looking at one problem, there. There are no known issues
      with using SIZEOF on local UDTs or with STATIC. Sounds more like your program
      data is getting trashed. I'd suggest that you check over the DECLAREs first and
      then take a look at the parameters being passed. There is most likely an error
      in one or the other.

      ------------------
      Tom Hanlin
      PowerBASIC Staff

      Comment


      • #4
        I agree, it does appear that there is some kind of data overlap
        that causes a UDT to become invalid, which explains why having one UDT local and another
        static fixes the problem.

        The function calls I'm using aren't the best documented on MSDN, with either incomplete
        or missing documentation, so it is possible that the UDTs are getting mangled there by
        design. I just wanted to see if anyone else had the same problem or if it was just my
        sometimes-quirky machine.

        Thanks!

        ------------------
        Mark Newman
        Mark Newman

        Comment


        • #5
          LOCAL variables are created on the stack, so this suggests a stack-related issue.

          Post the original C headers for the DLL and we'll see if we can spot anything...

          ------------------
          Lance
          PowerBASIC Support
          mailto:[email protected][email protected]</A>
          Lance
          mailto:[email protected]

          Comment


          • #6
            Here's the original C declares, followed by my PB translations. I've omitted the Unicode versions since I'm only using ANSI:

            Code:
            typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA_A {
                DWORD  cbSize;
                CHAR   DevicePath[ANYSIZE_ARRAY];
            } SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
               
            typedef SP_DEVICE_INTERFACE_DETAIL_DATA_A SP_DEVICE_INTERFACE_DETAIL_DATA;
            typedef PSP_DEVICE_INTERFACE_DETAIL_DATA_A PSP_DEVICE_INTERFACE_DETAIL_DATA;
               
               Type SP_DEVICE_INTERFACE_DETAIL_DATA
                  cbSize                  As Dword
                  DevicePath              As Asciiz * 256
               End Type
               (Note: The C version allocates DevicePath at runtime with some bizarre syntax;
               using a fixed size is ok as long as the size is sufficient.)
            ***
               
            typedef struct _SP_DEVICE_INTERFACE_DATA {
                DWORD cbSize;
                GUID  InterfaceClassGuid;
                DWORD Flags;
                DWORD Reserved;
            } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
               
               Type SP_DEVICE_INTERFACE_DATA
                  cbSize                  As Dword
                  InterfaceClassGuid      As GUID
                  Flags                   As Dword
                  Reserved                As Dword
               End Type
               
            ***
               
            typedef PVOID HDEVINFO;
               
            WINSETUPAPI
            HDEVINFO
            WINAPI
            SetupDiGetClassDevsA(
                IN LPGUID ClassGuid,  OPTIONAL
                IN PCSTR  Enumerator, OPTIONAL
                IN HWND   hwndParent, OPTIONAL
                IN DWORD  Flags
                );
            #define SetupDiGetClassDevs SetupDiGetClassDevsA
                
               Declare Function SetupDiGetClassDevs Cdecl Lib "Setupapi.dll" Alias "SetupDiGetClassDevsA" _
                  ( _
                  ByRef ClassGuid                     As GUID, _
                  ByRef Enumerator                    As Dword, _
                  ByVal hwndParent                    As Long, _
                  ByVal Flags                         As Dword _
                  ) As Dword
               
            ***
               
            WINSETUPAPI
            BOOL
            WINAPI
            SetupDiEnumDeviceInterfaces(
                IN  HDEVINFO                  DeviceInfoSet,
                IN  PSP_DEVINFO_DATA          DeviceInfoData,     OPTIONAL
                IN  LPGUID                    InterfaceClassGuid,
                IN  DWORD                     MemberIndex,
                OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
                );
               
               Declare Function SetupDiEnumDeviceInterfaces Cdecl Lib "Setupapi.dll" Alias "SetupDiEnumDeviceInterfaces" _
                  ( _
                  ByVal DeviceInfoSet                 As Dword, _
                  ByVal DeviceInfoData                As Dword, _
                  ByRef InterfaceClassGuid            As GUID, _
                  ByVal MemberIndex                   As Dword, _
                  ByRef DeviceInterfaceData           As SP_DEVICE_INTERFACE_DATA _
                  ) As Long
                
            ***
               
            WINSETUPAPI
            BOOL
            WINAPI
            SetupDiGetDeviceInterfaceDetailA(
                IN  HDEVINFO                           DeviceInfoSet,
                IN  PSP_DEVICE_INTERFACE_DATA          DeviceInterfaceData,
                OUT PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,     OPTIONAL
                IN  DWORD                              DeviceInterfaceDetailDataSize,
                OUT PDWORD                             RequiredSize,                  OPTIONAL
                OUT PSP_DEVINFO_DATA                   DeviceInfoData                 OPTIONAL
                );
            #define SetupDiGetDeviceInterfaceDetail SetupDiGetDeviceInterfaceDetailA     
               
               Declare Function SetupDiGetDeviceInterfaceDetail Cdecl Lib "Setupapi.dll" Alias "SetupDiGetDeviceInterfaceDetailA" _
                  ( _
                  ByVal DeviceInfoSet                 As Dword, _
                  ByRef DeviceInterfaceData           As SP_DEVICE_INTERFACE_DATA, _
                  ByRef DeviceInterfaceDetailData     As SP_DEVICE_INTERFACE_DETAIL_DATA, _
                  ByVal DeviceInterfaceDetailDataSize As Dword, _
                  ByRef RequiredSize                  As Dword, _
                  ByVal DeviceInfoData                As Dword _
                  ) As Long
                 
            ***
               
            WINSETUPAPI
            BOOL
            WINAPI
            SetupDiDestroyDeviceInfoList(
                IN HDEVINFO DeviceInfoSet
                );
               
               Declare Function SetupDiDestroyDeviceInfoList Cdecl Lib "Setupapi.dll" Alias "SetupDiDestroyDeviceInfoList" _
                  ( _
                  ByVal DeviceInfoSet                 As Dword _
                  ) As Long

            ------------------
            Mark Newman

            [This message has been edited by Mark Newman (edited April 11, 2001).]
            Mark Newman

            Comment


            • #7
              WINAPI specifies standard calling method. Take the CDECL out of those DECLAREs.


              ------------------
              Tom Hanlin
              PowerBASIC Staff

              Comment


              • #8
                WHAT???!!! <bang! thud!> The sounds you just heard were of me falling off my chair,
                striking my head on the desk on the way down. Fortunately, there's not much to damage in that
                part of my anatomy right now.

                I see what I did: In the C header file there's a line defining the WINSETUPAPI macro:

                #define WINSETUPAPI DECLSPEC_IMPORT

                So I opened up MSDN to search for 'DECLSPEC_IMPORT' and found a topic titled, "Export from a
                DLL Using __declspec(dllexport)". In this topic was this:

                __declspec(dllexport) void __cdecl Function1(void);

                A related topic showed the use of the companion '__declspec(dllimport)' keyword in the same
                manner. I see the '__cdecl' in the MSDN line and put in CDECL in the PB declares, not realizing
                that the 'void __cdecl' wasn't part of the macro.

                Gads.

                If I might be permitted one more question: How did this even work at all?? If the function
                parameters were placed on the stack in the wrong order, shouldn't there have been GPFs running
                amok, instead of my code working by using LOCAL and STATIC on the UDTs?

                I very much appreciate the help (and patience!) as I try to expand my usage of PB and do
                more with it.




                ------------------
                Mark Newman
                Mark Newman

                Comment


                • #9
                  I believe the parameter passing order is the same, it's just that the stack
                  is cleaned up differently. So it "kinda" worked for a while...

                  ------------------
                  Tom Hanlin
                  PowerBASIC Staff

                  Comment

                  Working...
                  X