Results 1 to 4 of 4

Thread: How to handle handles in vb6, differences during dev and when compiled

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Jan 2020
    Posts
    23

    How to handle handles in vb6, differences during dev and when compiled

    So I'm in charge of coming up with working examples of reading and writing from, and to an FTDI chip. there's two of them on a board that we can hook up using one USB cable.

    The FTDI chip ('ft232r') uses a device handle that I open, do something, and close. Each action will either wait for reading a response. So far all from the VB6 IDE.

    I'd rather just keep the handle open until the program would shut down. (If this would be an option, I just simply don't know enough about the subject). So we wouldn't have to open and close it every 10 or 20 ms.

    In my understanding, a handle could be open indefinitely, while no other application needs to make use of it. Which is the case, only my application uses it.

    When using a webcam, for instance, is the handle kept open as long as the webcam is active? or is the stream buffered constantly ( i don't think so but can't find information).

    Or can a handle be kept open 'indefinitely', until the program quits and no other application needs access?

    The 'locked device' happening inside the IDE: Is this just how the IDE is different because "Windows doesn't get to close it for me". Only reconnecting the USB cable will solve the locked device ( there might still be memory in use ).


    According to another 'source': All versions of Windows close kernel handles when an application crashes. Even Windows 95 did this. And certainly, anything based on the Windows NT kernel or later will close kernel handles on an app crash.

    But I'm not using a kernel handle am I? or is this just a way it is described. It's confusing to me.

    Or would/could this mean, that when my application is compiled, and it would crash, I just reopen the handle? I don't know how to test my application crashing while a handle is open.

    i wanted to add:
    Maybe the above is due to not knowing how to create a fatal error inside a compiled program. Because I could then test different use-case-scenario's. Maybe this is as easy as 'doing something wrong'. Like create a button that will assign something to an unassigned array?
    Or did I just answer my own question here?
    Last edited by rikdol; Nov 16th, 2020 at 06:16 AM.

  2. #2
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: How to handle handles in vb6, differences during dev and when compiled

    You can kill your application in Task Manager — this will be equivalent to it crashing and getting terminated by the OS itself.

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Jan 2020
    Posts
    23

    Re: How to handle handles in vb6, differences during dev and when compiled

    Thanks for the reply. This was the first thing I tested. But then I was not convinced it would 'simulate' a proper crash, now I know differently. And running a compiled app will indeed close any handles I may not have closed. So restarting the application will grant me access to the device.

    But why is this not taking place from within the IDE? isn't VB6 in fact a running process on it's own in which I start the same application?
    If the program ends within the IDE, deliberately or not, the handle isn't closed. not unless I restart VB6.exe

    If I try to close the handle during form load, I can't . Is this because I'm actually starting a different process from within the IDE?

    Restarting the IDE is needed to re-gain control of the device that I didn't close before.

    Why can't I close the handle to the device if I do a restart in between?
    Last edited by rikdol; Nov 16th, 2020 at 08:45 AM.

  4. #4
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: How to handle handles in vb6, differences during dev and when compiled

    Quote Originally Posted by rikdol View Post
    But why is this not taking place from within the IDE? isn't VB6 in fact a running process on it's own in which I start the same application?
    No, VB6 debugger is different that C/C++ or the C# debugger in Visual Studio. VB6 uses an *interpreter* to run you project inside its own process. VS compiles C/C++ to native code and C# to managed code and starts a *separate* process then attaches to it to be able to trace code, show variables, etc.

    That is why when you open a handle in VB6 IDE and press Stop button (or execute End statement in your code) the handle remains open as the OS is not terminating a process so not kernel handles get cleaned up.

    If you need such cleanup to happen automatically in VB6 IDE you can use Cleanup Thunk from MST. Here it is extracted in a separate .bas module:

    Code:
    Option Explicit
    
    '=========================================================================
    ' API
    '=========================================================================
    
    Private Const SIGN_BIT                      As Long = &H80000000
    '--- for thunks
    Private Const MEM_COMMIT                    As Long = &H1000
    Private Const PAGE_EXECUTE_READWRITE        As Long = &H40
    
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    Private Declare Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
    Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
    Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
    Private Declare Function GetProcByOrdinal Lib "kernel32" Alias "GetProcAddress" (ByVal hModule As Long, ByVal lpProcOrdinal As Long) As Long
    
    '=========================================================================
    ' Functions
    '=========================================================================
    
    Public Function InitCleanupThunk(ByVal hHandle As Long, sModuleName As String, sProcName As String) As IUnknown
        Dim STR_THUNK       As String: STR_THUNK = "6AAAAABag+oFgepQEDwBV1aLdCQUgz4AdCeL+oHHPBE8AYvCBcwQPAGri8IFCBE8AauLwgUYETwBq7kCAAAA86WBwjwRPAFSahD/Ugxai/iLwqu4AQAAAKuLRCQMq4tEJBCrg+8Qi0QkGIk4Xl+4UBE8AS1QEDwBwhAAkItEJAiDOAB1KoN4BAB1JIF4CMAAAAB1G4F4DAAAAEZ1EotUJAT/QgSLRCQMiRAzwMIMALgCQACAwgwAkItUJAT/QgSLQgTCBAAPHwCLVCQE/0oEi0IEdRL/cgj/UgyLVCQEiwpS/1EQM8DCBAAPHwA=" ' 25.3.2019 14:03:56
        Const THUNK_SIZE    As Long = 256
        Static hThunk       As Long
        Dim aParams(0 To 1) As Long
        Dim pfnCleanup      As Long
        Dim lSize           As Long
        
        #If ImplSelfContained Then
            If hThunk = 0 Then
                hThunk = pvThunkGlobalData("InitCleanupThunk")
            End If
        #End If
        If hThunk = 0 Then
            hThunk = pvThunkAllocate(STR_THUNK, THUNK_SIZE)
            If hThunk = 0 Then
                Exit Function
            End If
            aParams(0) = GetProcAddress(GetModuleHandle("ole32"), "CoTaskMemAlloc")
            aParams(1) = GetProcAddress(GetModuleHandle("ole32"), "CoTaskMemFree")
            #If ImplSelfContained Then
                pvThunkGlobalData("InitCleanupThunk") = hThunk
            #End If
        End If
        If Left$(sProcName, 1) = "#" Then
            pfnCleanup = GetProcByOrdinal(GetModuleHandle(sModuleName), Mid$(sProcName, 2))
        Else
            pfnCleanup = GetProcAddress(GetModuleHandle(sModuleName), sProcName)
        End If
        If pfnCleanup <> 0 Then
            lSize = CallWindowProc(hThunk, hHandle, pfnCleanup, VarPtr(aParams(0)), VarPtr(InitCleanupThunk))
            Debug.Assert lSize = THUNK_SIZE
        End If
    End Function
    
    Private Function pvThunkAllocate(sText As String, Optional ByVal Size As Long) As Long
        Static Map(0 To &H3FF) As Long
        Dim baInput()       As Byte
        Dim lIdx            As Long
        Dim lChar           As Long
        Dim lPtr            As Long
        
        pvThunkAllocate = VirtualAlloc(0, IIf(Size > 0, Size, (Len(sText) \ 4) * 3), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
        If pvThunkAllocate = 0 Then
            Exit Function
        End If
        '--- init decoding maps
        If Map(65) = 0 Then
            baInput = StrConv("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", vbFromUnicode)
            For lIdx = 0 To UBound(baInput)
                lChar = baInput(lIdx)
                Map(&H0 + lChar) = lIdx * (2 ^ 2)
                Map(&H100 + lChar) = (lIdx And &H30) \ (2 ^ 4) Or (lIdx And &HF) * (2 ^ 12)
                Map(&H200 + lChar) = (lIdx And &H3) * (2 ^ 22) Or (lIdx And &H3C) * (2 ^ 6)
                Map(&H300 + lChar) = lIdx * (2 ^ 16)
            Next
        End If
        '--- base64 decode loop
        baInput = StrConv(Replace(Replace(sText, vbCr, vbNullString), vbLf, vbNullString), vbFromUnicode)
        lPtr = pvThunkAllocate
        For lIdx = 0 To UBound(baInput) - 3 Step 4
            lChar = Map(baInput(lIdx + 0)) Or Map(&H100 + baInput(lIdx + 1)) Or Map(&H200 + baInput(lIdx + 2)) Or Map(&H300 + baInput(lIdx + 3))
            Call CopyMemory(ByVal lPtr, lChar, 3)
            lPtr = (lPtr Xor SIGN_BIT) + 3 Xor SIGN_BIT
        Next
    End Function
    Here is a sample snippet how to use it to call CloseHandle API function for an hFile handle on IDE debug session termination:

    Code:
    Option Explicit
    
    Private Const OPEN_EXISTING                 As Long = 3
    Private Const GENERIC_READ                  As Long = &H80000000
    Private Const FILE_SHARE_READ               As Long = &H1
    Private Const FILE_SHARE_WRITE              As Long = &H2
    
    Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
    
    Private m_pCleanup1 As IUnknown
    
    Private Sub Form_Load()
        Dim hFile           As Long
        
        hFile = CreateFile(App.Path & "\Form1.frm", GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)  ' FILE_SHARE_READ Or FILE_SHARE_WRITE
        If hFile = -1 Then
            MsgBox "Cannot open file", vbExclamation
            Exit Sub
        End If
        Set m_pCleanup1 = InitCleanupThunk(hFile, "kernel32", "CloseHandle")
        If MsgBox("Do you want to forcibly End debug session?", vbYesNo Or vbQuestion) = vbYes Then
            End
        End If
        '--- IUnknown::Release calls CloseHandle(hFile) in kernel32.dll
        Set m_pCleanup1 = Nothing
    End Sub
    cheers,
    </wqw>

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width