Results 1 to 8 of 8

Thread: FindResource and the IDE

  1. #1

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,915

    FindResource and the IDE

    Okay, I need a function that'll just tell me whether a file is in my resources or not.

    I'd prefer not to use LoadResData with error trapping because some of my resource files are somewhat large. Therefore, my first idea was to use the FindResource API call. However, this only works once the program is compiled.

    So, what I'd like as a ResourceExists(sFileName As String, sResourceType As String) As Boolean function that works the same in the IDE as compiled.

    I'm going to do it with error trapping (and LoadResData) for now, but I'd sure like a better solution.

    Thanks In Advance,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: FindResource and the IDE

    Elroy, you know better than post a question, as its own thread, in the codebank

    But I'll add this while you consider reporting your own thread to be moved...
    You can't check a file name. The file name is not preserved when you add something to a resource file. In short, what you are asking is very possible doing a byte-comparison between the file contents and res file content. However, one needs to be pretty familiar with how stuff is added there. Icons/Cusors are separated into separate resources (per image in the file), bitmaps have the file header stripped off for example.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: FindResource and the IDE

    LaVolpe's got it. I bet you can add the same file multiple times if you want even.

  4. #4

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,915

    Re: FindResource and the IDE

    Quote Originally Posted by LaVolpe View Post
    Elroy, you know better than post a question, as its own thread, in the codebank

    But I'll add this while you consider reporting your own thread to be moved...
    You can't check a file name. The file name is not preserved when you add something to a resource file. In short, what you are asking is very possible doing a byte-comparison between the file contents and res file content. However, one needs to be pretty familiar with how stuff is added there. Icons/Cusors are separated into separate resources (per image in the file), bitmaps have the file header stripped off for example.
    Ahhh, I obviously wasn't clear with my original question.

    Here's the scenario. First, everything I'm talking about is a "Custom" resource. They're just files that I'll be adding. It's an ongoing project that will evolve over time, with more files completed as the project progresses.

    What I wanted to do was to complete all the coding for all the files (i.e., the "Custom resources) before these files were actually completed. Others are working on the actual files. They're just word documents or PDF files.

    So ... if the file wasn't found in the VB6 project's resources, I just wanted to give the user a nice message saying that this one isn't yet done, rather than an ugly error. I suppose I could rewrite my routines that fetch these files to include a bit of error trapping, but it just seems that I should be able to "ask" if the file is in the VB6 project's resources without actually loading the file.

    Here's the code I've got now:

    Code:
    
    Public Function ResourceFileExists(sFileName As String, sResourceType As String) As Boolean
        Dim bb() As Byte
        '
        On Error GoTo DidntFindIt
        bb = LoadResData(Replace$(sFileName, " ", ""), sResourceType) ' Returns a Byte array.
        ResourceFileExists = True
    DidntFindIt:
    End Function
    
    I just thought it would be nice if I didn't have to load the file to answer this question. I can do it with FindResource once the project is compiled, but I do a great deal of testing in the IDE (as I suspect we all do), so I need it to work the same in the IDE as compiled.

    p.s. I notified the moderators.

    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: FindResource and the IDE

    I can whip something up since I've got VB resource file parsers on-hand. Since icons/cursors/bitmaps aren't in play, makes it easier. However, you are comparing byte-by-byte. That would mean that if you changed one character in your Word doc outside of the resource, it wouldn't find it inside the resource. Is that what you're after?

    What I will whip up is for uncompiled resources only. Adding for compiled exe resources isn't that difficult since I have those routines also. But gotta ask, why would you do this after resource is compiled? I'd think you may want to check the compiled exe from outside of the exe to see if you have the desired resource(s), but run from within the exe?
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,915

    Re: FindResource and the IDE

    LaVolpe,

    Noooo, wait. It's simpler than that. All I want to know is, "is this file name, under this resource custom type in my resource file (or not)?" My error trapping routine above works, but it's slow because it reads the file to get it done. There's got to be a way to do it without reading the file.

    Thanks for Helping,
    Elroy

    EDIT1: I'll manage updates to the files in a separate way. I don't care if it's an old version of the file in my resources. I just want to know if any version is there, or not.

    EDIT2:
    Quote Originally Posted by LaVolpe View Post
    But gotta ask, why would you do this after resource is compiled?
    Yeah, I know. It doesn't make a great deal of sense, but it's about managing the phases of this project. In many cases, I know what the names of the files are, but I don't have them yet. I just want to get it coded, and then have a VB6 program that extracts the resource "if it's in the internal resources". If it's not, it reports that fact to the user.
    Last edited by Elroy; Oct 24th, 2017 at 05:29 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: FindResource and the IDE

    I think I got you now, after looking closer at your code. It appears you are using the file name as the resource ID.

    In the following, it will create a collection of resources (custom only) in this format: ResourceType:ResourceID. You can use the collection to test for any 'filename' you are looking for, with error testing:
    Code:
        On Error Resume Next
        bExists = (m_ResItems.Item(sResourceType & ":" & Replace$(sFileName, " ", "")) <> "")
        If Error Then Err.Clear
    To test this out, add this code in a form
    Code:
    Option Explicit
    
    Private Declare Function EnumResourceNames Lib "kernel32.dll" Alias "EnumResourceNamesW" (ByVal hModule As Long, ByVal lpType As Long, ByVal lpEnumFunc As Long, ByRef lParam As Any) As Long
    Private Declare Function EnumResourceTypes Lib "kernel32.dll" Alias "EnumResourceTypesW" (ByVal hModule As Long, ByVal lpEnumFunc As Long, ByRef lParam As Any) As Long
    Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
    Private Declare Function LoadLibraryEx Lib "kernel32.dll" Alias "LoadLibraryExW" (ByVal lpLibFileName As Long, ByVal hFile As Long, ByVal dwFlags As Long) As Long
    
    Private Declare Function GetFileSize Lib "kernel32.dll" (ByVal hFile As Long, ByRef lpFileSizeHigh As Long) As Long
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
    Private Declare Function ReadFile Lib "kernel32.dll" (ByVal hFile As Long, ByRef lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, ByRef lpNumberOfBytesRead As Long, Optional ByVal lpOverlapped As Long) As Long
    Private Declare Function SetFilePointer Lib "kernel32.dll" (ByVal hFile As Long, ByVal lDistanceToMove As Long, ByRef lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long
    Private Declare Function CreateFileW Lib "kernel32" (ByVal lpFileName As Long, 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 Declare Function GetFileAttributesW Lib "kernel32.dll" (ByVal lpFileName As Long) As Long
    Private Const FILE_BEGIN As Long = 0
    Private Const FILE_CURRENT As Long = 1
    Private Const FILE_END As Long = 2
    Private Const INVALID_HANDLE_VALUE = -1&
    
    Private m_ResItems As Collection
    
    Private Function pvParseResEXE(FileName As String) As Boolean
    
        Dim hMod As Long, n As Long, t As Long
        Dim cResType As Collection, cResItems As Collection
        Const LOAD_LIBRARY_AS_DATAFILE As Long = &H2
        
        Set m_ResItems = New Collection
        If Not FileName = "" Then       ' else querying itself
            hMod = LoadLibraryEx(StrPtr(FileName), 0&, LOAD_LIBRARY_AS_DATAFILE)
            If hMod = 0 Then Exit Function
        End If
        
        Set cResType = New Collection
        EnumResourceTypes hMod, AddressOf EnumResourceTypesProc, cResType
        If cResType.Count Then
            For t = 1 To cResType.Count
                Set cResItems = New Collection
                EnumResourceNames hMod, StrPtr(cResType(t)), AddressOf EnumResNameProc, cResItems
                For n = 1 To cResItems.Count
                    m_ResItems.Add cResType(t) & ":" & cResItems(n)
                Next
            Next
        End If
        If hMod Then FreeLibrary hMod
    
    End Function
    
    Private Function pvParseResFile(hFile As Long) As Boolean
    
        Dim lOffset As Long, lHdrSize As Long
        Dim lDataSize As Long, iChar As Long
        Dim vType As Variant, vName As Variant
        Dim lEOF As Long, c As Long, aData() As Byte
        Dim lRead As Long, sData As String
        
        Set m_ResItems = New Collection
        lEOF = GetFileSize(hFile, lRead)
        If lRead > 0& Then Exit Function    ' not prepared to handle 2+ GB resource files
        
        SetFilePointer hFile, 0&, 0&, FILE_BEGIN
        Do
            ReadFile hFile, lDataSize, 4&, lRead
            If lRead < 4& Then
                ' allow DWORD misaligned final resource; can be fixed when re-writing
                If lEOF < lOffset Then Exit Do
                Exit Function
            End If ' FYI: lHdrSize should already be DWord sized (we'll allow this to be wrong)
            ReadFile hFile, lHdrSize, 4&, lRead: If lRead < 4& Then Exit Function
            If lHdrSize < ((lHdrSize + 3&) And Not 3&) Then lHdrSize = ((lHdrSize + 3&) And Not 3&)
            If lHdrSize < 32 Or lDataSize < 0& Then Exit Function
            If lOffset + lHdrSize + ((lDataSize + 3&) And Not 3&) > lEOF Then Exit Function
            
            ' get the resource type
            ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
            If iChar = &HFFFF& Then
                ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
                vType = iChar
            Else
                sData = vbNullString
                For c = 2& To lHdrSize - 28& Step 2&
                    sData = sData & ChrW$(iChar)
                    ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
                    If iChar = 0 Then Exit For
                Next
                vType = sData
            End If
    
            If VarType(vType) = vbString Then
                ' get the resource name
                ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
                If iChar = &HFFFF& Then
                    ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
                    vName = iChar
                Else
                    sData = vbNullString
                    c = SetFilePointer(hFile, 0&, 0&, FILE_CURRENT)
                    For c = 2& To (lOffset + lHdrSize) - c - 14& Step 2&
                        sData = sData & ChrW$(iChar)
                        ReadFile hFile, iChar, 2&, lRead: If lRead < 2& Then Exit Function
                        If iChar = 0& Then Exit For
                    Next
                    vName = sData
                    m_ResItems.Add vType & ":" & vName
                End If
            End If
            lOffset = lOffset + lHdrSize + ((lDataSize + 3&) And Not 3&)
            If lOffset >= lEOF Then Exit Do
            SetFilePointer hFile, lOffset - SetFilePointer(hFile, 0&, 0&, FILE_CURRENT), 0&, FILE_CURRENT
        Loop
    
    ExitRoutine:
    End Function
    
    Private Function pvOpenFile(ByVal FileName As String) As Long
    
        ' Function uses APIs to read/create files with unicode support
    
        Const GENERIC_READ As Long = &H80000000
        Const OPEN_EXISTING = &H3
        Const FILE_SHARE_READ = &H1
        Const GENERIC_WRITE As Long = &H40000000
        Const FILE_SHARE_WRITE As Long = &H2
        Const CREATE_ALWAYS As Long = 2
        Const FILE_ATTRIBUTE_ARCHIVE As Long = &H20
        Const FILE_ATTRIBUTE_HIDDEN As Long = &H2
        Const FILE_ATTRIBUTE_READONLY As Long = &H1
        Const FILE_ATTRIBUTE_SYSTEM As Long = &H4
        Const FILE_ATTRIBUTE_NORMAL = &H80&
    
        Dim Flags As Long, Access As Long
        Dim Disposition As Long, Share As Long
        
        Access = GENERIC_READ Or GENERIC_WRITE
        If Not ((GetFileAttributesW(StrPtr(FileName)) = INVALID_HANDLE_VALUE)) Then
            Disposition = OPEN_EXISTING
            Flags = FILE_ATTRIBUTE_ARCHIVE Or FILE_ATTRIBUTE_HIDDEN Or FILE_ATTRIBUTE_NORMAL _
                    Or FILE_ATTRIBUTE_READONLY Or FILE_ATTRIBUTE_SYSTEM
            pvOpenFile = CreateFileW(StrPtr(FileName), Access, Share, ByVal 0&, Disposition, Flags, 0&)
        End If
        
    End Function
    Add this in a module
    Code:
    Option Explicit
    Private Declare Function lstrlenW Lib "kernel32.dll" (ByVal lpString As Long) As Long
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal length As Long)
    
    Public Function EnumResNameProc(ByVal hModule As Long, ByVal lpszType As Long, _
                                    ByVal lpszName As Long, ByRef lParam As Collection) As Long
        
        Dim lLen As Long, sID As String
        If (lpszName And &HFFFF0000) = 0& Then
            lParam.Add "#" & lpszName
            EnumResNameProc = 1&
        Else
            lLen = lstrlenW(lpszName)
            If lLen Then
                sID = Space$(lLen)
                CopyMemory ByVal StrPtr(sID), ByVal lpszName, lLen + lLen
                lParam.Add sID
                EnumResNameProc = 1&
            End If
        End If
    End Function
    
    Public Function EnumResourceTypesProc(ByVal hModule As Long, ByVal lpszType As Long, ByRef lParam As Collection) As Long
    
        Dim lLen As Long, sID As String
        If (lpszType And &HFFFF0000) = 0& Then
            'lParam.Add "#" & lpszType ' << do nothing; want "custom" types; therefore, string types
            EnumResourceTypesProc = 1&
        Else
            lLen = lstrlenW(lpszType)
            If lLen Then
                sID = Space$(lLen)
                CopyMemory ByVal StrPtr(sID), ByVal lpszType, lLen + lLen
                lParam.Add sID
                EnumResourceTypesProc = 1&
            End If
        End If
    
    End Function
    I've included a pvOpenFile routine that is unicode compatible; though that may not matter to you. However, included APIs must be used to read the file due to the code I provided.

    If testing a resource file, call pvOpenFile passing it the resource path/file to retrieve a handle. Pass that handle to the pvParseResFile routine and close the handle after return. The m_resItems collection will be filled or have a count of zero
    Code:
    Dim hFile As Long
       hFile = pvOpenFile(yourResourceFileName)
       If hFile = 0 Or hFile = INVALID_HANDLE_VALUE Then
          ' error - file may be locked or bad file name passed. deal with it
       Else
          pvParseResFile hFile
          CloseHandle hFile
       End If
       ' now you can test any/all your file names against the collection
    If testing a compiled executable, pass the executable file name or empty string if wanting to test against itself to pvParseResEXE
    Code:
        pvParseResEXE "" ' to test its own compiled resources
       ' now you can test any/all your file names against the collection
    Edited: I tweaked the two parsing routines to only look for custom resources. Custom resources are defined as those having string names, i.e., "Custom". Non-custom are those with integer names, i.e., RT_BITMAP (Bitmaps in VB's resource editor).

    Last but not least, an alternate way of comparing compiled resources of the exe itself would be to use FindResource API. This would negate the module and pvParseResEXE routine. The module is only needed if you want a collection to test against.
    Code:
    Private Declare Function FindResource Lib "kernel32.dll" Alias "FindResourceW" (ByVal hInstance As Long, ByVal lpName As Long, ByVal lpType As Long) As Long
    
    example: bExists = (FindResource(0&, StrPtr(resourceType), StrPtr(fileName)) <> 0)
    Offhand, I cannot see a simple way of replacing LoadResData() with a similar/quicker method while in the IDE. Parsing a resource file isn't ideal from within the project because you'd have to hard code its path/filename. Only other quickie I can think of is to create your own custom resource that only contains the files you've included, kinda like an index. Then you could use LoadResData() on it and extract the filenames. At least that resource should be relatively small in size. The code I posted above could be ideal for querying the resource file and compiled executable from outside -- as a quality control measure. Don't worry about the effort of putting together the sample code, just had to cobble it together from existing projects.
    Last edited by LaVolpe; Oct 24th, 2017 at 07:14 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  8. #8

    Thread Starter
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,915

    Re: FindResource and the IDE

    LaVolpe,

    Thank you sooo much. I'm a bit distracted with other stuff, but I'll report back on how this goes as soon as I have a chance.

    Again, Thank You!
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

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