Atlanta Custom Software Development 

 
   Search        Code/Page
 

User Login
Email

Password

 

Forgot the Password?
Services
» Web Development
» Maintenance
» Data Integration/BI
» Information Management
Programming
  Database
Automation
OS/Networking
Graphics
Links
Tools
» Regular Expr Tester
» Free Tools


A Resource File is a repository in executable file (exe/dll/ocx) where you can store images, sounds, videos, data, or whatever you like. VB provides addin to modify resource during design time but what if you want to modify it during runtime. Win32 API is the solution to this problem. There are 3 main APIs (BeginUpdateResource, UpdateResource and EndUpdateResource) which you can use to modify resource programatically which can be stored in any executable file. From this demo you will learn the following items
  1. Modify (Add,Update or Delete) string resource stored in any exe/dll/ocx
  2. Modify (Add,Update or Delete) bitmap resource stored in any exe/dll/ocx
  3. List all string resource items stored in any exe/dll/ocx
  4. Display a single string resource item using LoadString API
  5. Display Bitmap resource item using LoadImage and other GDI apis

Retriving resource item is comparatively easy in VB if you are going to retrive from the same Application file. You can use inbuilt VB functions like LoadResPicture, LoadResString or LoadResData to retrive resource item from the same application file but if you need to access resource from different executable file then you need Win32 APIs like LoadString, LoadImage etc...

This article will show you how to modify Bitmap and String resource from any executable file using API. Storing Bitmap is comparatively easy but to store string in to the resource file requires good understanding of string table format.

String table in Resource file

The smallest granularity of string resource that can be loaded/updated is a block. Each block is identified by an ID, starting with 1. You need to use the block ID when calling FindResource(), LoadResource(), UpdateResource(). A string with ID, nStringID, is in the block with ID, nBlockID, given by the following formula:

Click here to copy the following block
nBlockID = (nStringID / 16) + 1

Note integer division.

A block of string resource is laid out as follows:

Each block has NO_OF_STRINGS_PER_BLOCK (= 16) strings. Each string is represented as an ordered pair, (LENGTH, TEXT). The LENGTH is a WORD that specifies the size, in terms of number of characters, of the string that follows. TEXT follows the LENGTH and is a sequence of UNICODE characters, NOT terminated by a NULL character.Any TEXT may be of zero-length, in which case, LENGTH is zero. An executable does not have a string table block with ID, nBlockID, if it does not have any strings with IDs - ((nBlockID - 1) * 16) thru' ((nBlockID * 16) - 1). This format is the same for Windows NT, Windows 95 & Windows 98. Yes, strings in a resource are internally stored in UNICODE format even in Windows 95 & Windows 98.

Step-By-Step Example

- Create one standard exe project
- Add one command button and one picturebox control on the form1
- Add the following code in form1
- Modify sResExeFilePath to any sample exe whose resource you want to modify
- Modify sBMPFileToLoadPath to any existing BMP path. This BMP will be loaded into the exe resource as ID=101 so make sure that target exe/dll doesn't have Bitmap resource with 101 ID otherwise it will be overwritten

Click here to copy the following block
Private Type BITMAP
  bmType As Long      ' this must be zero
  bmWidth As Long     ' bitmap width
  bmHeight As Long     ' bitmap height
  bmWidthBytes As Long   ' bytes in horiz raster line
  bmPlanes As Integer   ' number of color planes
  bmBitsPixel As Integer  ' number of bits per pixel
  bmBits As Long      ' address of pixel data in memory
End Type

Private Type StringTable
  id As Long
  Text As String
End Type

Private Const IMAGE_ARCHIVE_START_SIZE = 8
Private Const IMAGE_BITMAP = 0
Private Const LR_CREATEDIBSECTION = &H2000

' Predefined Resource Types
Private Const DIFFERENCE = 11
Private Const RT_ACCELERATOR = 9&
Private Const RT_ANICURSOR = (21)
Private Const RT_ANIICON = (22)
Private Const RT_BITMAP = 2&
Private Const RT_CURSOR = 1&
Private Const RT_DIALOG = 5&
Private Const RT_DLGINCLUDE = 17
Private Const RT_ICON = 3&
Private Const RT_FONT = 8&
Private Const RT_FONTDIR = 7&
Private Const RT_GROUP_CURSOR = (RT_CURSOR + DIFFERENCE)
Private Const RT_GROUP_ICON = (RT_ICON + DIFFERENCE)
Private Const RT_HTML = 23
Private Const RT_MENU = 4&
Private Const RT_MESSAGETABLE = 11
Private Const RT_PLUGPLAY = 19
Private Const RT_RCDATA = 10&
Private Const RT_STRING = 6&
Private Const RT_VERSION = 16

Private Const RT_MYOWN_TYPE1 = 10001
Private Const RT_MYOWN_TYPE2 = 10002

Private Const ENGLISH_US = 1033


Private Declare Function BeginUpdateResource Lib "kernel32" Alias "BeginUpdateResourceA" ( _
    ByVal pstrFileName As String, ByVal bDeleteExistingResources As Long) As Long

Private Declare Function UpdateResource Lib "kernel32" Alias "UpdateResourceA" ( _
    ByVal hUpdate As Long, ByVal lpType As Long, ByVal lpName As Long, _
    ByVal wLanguage As Integer, lpData As Any, ByVal cbData As Long) As Long

Private Declare Function EndUpdateResource Lib "kernel32" Alias "EndUpdateResourceA" ( _
    ByVal hUpdate As Long, ByVal fDiscard As Long) As Long

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" ( _
    ByVal lpLibstrFileName As String) As Long

Private Declare Function FindResourceEx Lib "kernel32" Alias "FindResourceExA" ( _
    ByVal hModule As Long, ByVal lpType As Long, ByVal lpName As Long, _
    ByVal wLanguage As Long) As Long

Private Declare Function LoadResource Lib "kernel32" ( _
    ByVal hInstance As Long, ByVal hResourceInfo As Long) As Long

Private Declare Function LockResource Lib "kernel32" ( _
    ByVal hResourceData As Long) As Long

Private Declare Function SizeofResource Lib "kernel32" ( _
    ByVal hInstance As Long, ByVal hResourceInfo As Long) As Long

Private Declare Function FreeLibrary Lib "kernel32" ( _
    ByVal hLibModule As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    Destination As Any, Source As Any, ByVal Length As Long)

'//APIs to display Bitmap from Resource

Private Declare Function BitBlt Lib "gdi32.dll" ( _
    ByVal hDestDC As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal hSrcDC As Long, _
    ByVal xSrc As Long, _
    ByVal ySrc As Long, _
    ByVal dwRop As Long) As Long

Private Declare Function CreateCompatibleDC Lib "gdi32.dll" ( _
    ByVal hdc As Long) As Long

Private Declare Function DeleteDC Lib "gdi32.dll" ( _
    ByVal hdc As Long) As Long

Private Declare Function DeleteObject Lib "gdi32.dll" ( _
    ByVal hObject As Long) As Long

Private Declare Function LoadImage Lib "user32.dll" Alias "LoadImageA" ( _
    ByVal hInst As Long, _
    ByVal lpsz As String, _
    ByVal un1 As Long, _
    ByVal n1 As Long, _
    ByVal n2 As Long, _
    ByVal un2 As Long) As Long

Private Declare Function SelectObject Lib "gdi32.dll" ( _
    ByVal hdc As Long, _
    ByVal hObject As Long) As Long

Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal _
    hObject As Long, ByVal nCount As Long, lpObject As Any) As Long

'//API To display string item from resource
Private Declare Function LoadString Lib "user32.dll" Alias "LoadStringA" ( _
    ByVal hInstance As Long, _
    ByVal wID As Long, _
    ByVal lpBuffer As String, _
    ByVal nBufferMax As Long) As Long

'//1033=ENGLISH (US)
Public Function StringResourceModify(strResExePath As String, id As Integer, _
  ByVal strText As String, Optional LangID As Long = ENGLISH_US) As Boolean

  Dim ret As Long
  Dim hResource As Long
  Dim x As Long
  Dim iGroup As Integer
  Dim hObject As Long
  Dim hResourceData As Long
  Dim lpResourceData As Long
  Dim cbResource As Long
  Dim hModule As Long
  Dim lpData() As Byte
  Dim lpReadData() As Byte
  Dim cbText As Integer

  If id < 1 Then Exit Function

  'Calculate # of groups of strings
  iGroup = Int(id / 16&) + 1
  'Open the file
  hModule = LoadLibrary(strResExePath)
  hObject = FindResourceEx(hModule, RT_STRING, iGroup, LangID)  '//6=StringType
  hResourceData = LoadResource(hModule, hObject)
  lpResourceData = LockResource(hResourceData)
  cbResource = SizeofResource(hModule, hObject)

  If cbResource <= 32 Or hObject = 0 Then
    cbResource = 32& + Len(strText) * 2&
    ReDim lpData(cbResource - 1)
    cbText = Len(strText)
    CopyMemory lpData(2& * (id - (iGroup - 1) * 16&)), cbText, 2&
    If Len(strText) Then
      CopyMemory lpData(2& + 2& * (id - (iGroup - 1) * 16&)), ByVal StrPtr(strText), Len(strText) * 2
    End If
  Else
    ReDim lpReadData(cbResource - 1)
    CopyMemory lpReadData(0), ByVal lpResourceData, cbResource

    Dim countX As Long
    Dim CHECKLNG As Integer
    For x = 0 To (id - (iGroup - 1) * 16&) - 1
      CopyMemory CHECKLNG, lpReadData(countX), 2&
      countX = countX + 2 + CHECKLNG * 2
    Next
    CopyMemory CHECKLNG, lpReadData(countX), 2&
    ReDim lpData(countX + 2 + Len(strText) * 2 + (cbResource - (countX + 2 + CHECKLNG * 2)) - 1)
    CopyMemory lpData(0), lpReadData(0), countX
    cbText = Len(strText)
    CopyMemory lpData(countX), cbText, 2&
    If Len(strText) Then
      CopyMemory lpData(countX + 2), ByVal StrPtr(strText), Len(strText) * 2
    End If
    If (cbResource - (countX + 2 + CHECKLNG * 2)) > 0 Then
      CopyMemory lpData(countX + 2 + Len(strText) * 2), lpReadData(countX + 2 + CHECKLNG * 2), (cbResource - (countX + 2 + CHECKLNG * 2))
    End If
  End If

  'Free the loaded exe/dll file
  FreeLibrary hModule

  'Start resource update to the exe/dll
  hResource = BeginUpdateResource(strResExePath, ByVal 0&)

  'Update the ressource iGroup
  ret = UpdateResource(hResource, 6&, CLng(iGroup), CInt(LangID), lpData(0), UBound(lpData) + 1)

  'This will actually write the update to the disk and end the resource update process
  ret = EndUpdateResource(hResource, ByVal 0&)

  StringResourceModify = ret
End Function

Private Function StringResourceList(strFileName As String, Optional LangID As Long = ENGLISH_US) As StringTable()
  Dim ret As Long
  Dim hResource As Long
  Dim x As Long
  Dim iGroup As Integer
  Dim hObject As Long
  Dim hResourceData As Long
  Dim lpResourceData As Long
  Dim cbResource As Long
  Dim hModule As Long
  Dim lpData() As Byte
  Dim lpReadData() As Byte
  Dim Out() As StringTable
  Dim countX As Long
  Dim CHECKLNG As Integer
  Dim temp As String

  ReDim Out(0)
  hModule = LoadLibrary(strFileName)
  For iGroup = 1 To 4096
    hObject = FindResourceEx(hModule, 6&, iGroup, LangID)
    hResourceData = LoadResource(hModule, hObject)
    lpResourceData = LockResource(hResourceData)
    cbResource = SizeofResource(hModule, hObject)
    If cbResource >= 31 And hObject <> 0 Then
      ReDim lpReadData(cbResource - 1)
      CopyMemory lpReadData(0), ByVal lpResourceData, cbResource

      countX = 0
      x = 0
      Do While countX < UBound(lpReadData)
        CopyMemory CHECKLNG, lpReadData(countX), 2&
        countX = countX + 2
        If CHECKLNG Then
          ReDim Preserve Out(UBound(Out) + 1)
          Out(UBound(Out)).id = (iGroup - 1) * 16& + x
          temp = Space(CHECKLNG * 2)
          CopyMemory ByVal StrPtr(temp), lpReadData(countX), CHECKLNG * 2
          Out(UBound(Out)).Text = temp
          countX = countX + CHECKLNG * 2
        End If
        x = x + 1
      Loop
    End If
  Next
  FreeLibrary hModule
  StringResourceList = Out
End Function


Private Function BitmapResourceModify(strResExePath As String, strFileToLoad As String, _
  Optional nResType As Long = RT_BITMAP, Optional nID As Long = 101, Optional bDelete As Boolean = False) As Boolean

  Dim nFile As Long
  Dim Data() As Byte
  Dim arrSize As Long
  Dim ret As Long
  Dim Handle As Long

  nFile = FreeFile

  '//We need to pass byte buffer so create a ByteArry from file
  Open strFileToLoad For Binary As nFile
  arrSize = LOF(nFile) - 14
  ReDim Data(0 To arrSize - 1)
  Get nFile, 15, Data
  Close nFile

  Handle = BeginUpdateResource(strResExePath, 0)  '//0=Dont delete existing resource items
  If Handle = 0 Then Exit Function

  If bDelete = False Then
    '//Add/Modify
    ret = UpdateResource(Handle, ByVal nResType, ByVal nID, 1033, Data(0), arrSize)
  Else
    '//To Delete Resource item pass lpData=ByVal 0& (NULL) and cbData=0
    ret = UpdateResource(Handle, ByVal nResType, ByVal nID, 1033, ByVal 0&, 0)
  End If

  ret = EndUpdateResource(Handle, 0)
  BitmapResourceModify = ret
End Function

Sub DisplayBitmapRes(hDcDisplay As Long, sResFile As String, ResId As Long)
  Const IMAGE_BITMAP = 0&
  Const LR_CREATEDIBSECTION = &H2000

  Dim hDLL As Long
  Dim sID As String
  Dim sIdent102 As String
  Dim hMemDC As Long
  Dim lret As Long
  Dim hBmp As Long
  Dim oldhBmp As Long
  Dim picwid As Long, pichgt As Long
  Dim BMP As BITMAP

  sID = "#" & ResId    '//Name is in #xxxx format

  hDLL = LoadLibrary(sResFile)

  ' Could use LoadBitmap but it has been superceded by
  LoadImage which is more flexible.
  ' Hbmp = LoadBitmap(hDLL, sID)

  ' First bitmap in DLL
  hBmp = LoadImage(hDLL, sID, IMAGE_BITMAP, _
      0, 0, LR_CREATEDIBSECTION)

  GetObjectAPI hBmp, Len(BMP), BMP

  picwid = BMP.bmWidth
  pichgt = BMP.bmHeight

  ' Blit it to a pictureBox
  hMemDC = CreateCompatibleDC(hDcDisplay)
  oldhBmp = SelectObject(hMemDC, hBmp)
  lret = BitBlt(hDcDisplay, 0, 0, picwid, pichgt, _
      hMemDC, 0, 0, vbSrcCopy)

  DeleteObject hBmp

  ' Clean Up
  SelectObject hMemDC, oldhBmp
  DeleteDC hMemDC
  DeleteObject hBmp
  FreeLibrary hDLL
End Sub

Sub DisplayStringRes(sResFile As String, ResId As Long)
  Dim c As Integer, s As String, id As Long, hDLL As Long
  c = 1024
  s = String(c, 0)
  hDLL = LoadLibrary(sResFile)
  c = LoadString(hDLL, ResId, s, c)
  MsgBox s
  FreeLibrary hDLL
End Sub

Private Sub Command1_Click()
  Dim sResExeFilePath As String
  Dim sBMPFileToLoadPath As String

  sResExeFilePath = App.Path & "\test.exe"
  sBMPFileToLoadPath = App.Path & "\bmp_to_load.bmp"

  '//Note: ID Must be unique with in the same group of resource
  '//otherwise resource item will be overwritten by update

  '//Save Bitmap Resource Demo
  MsgBox BitmapResourceModify(sResExeFilePath, sBMPFileToLoadPath, RT_BITMAP, 101), , "BitmapResourceModify"
  '//Delete Bitmap Resource Demo
  '//MsgBox BitmapResourceModify(sResExeFilePath, sBMPFileToLoadPath, RT_BITMAP, 101,True)

  '//Save String Resource Demo
  MsgBox StringResourceModify(sResExeFilePath, 101, "This is test1"), , "StringResourceModify"
  MsgBox StringResourceModify(sResExeFilePath, 102, "This is test2"), , "StringResourceModify"
  MsgBox StringResourceModify(sResExeFilePath, 103, "This is test3"), , "StringResourceModify"

  '//To remove string ID=102 just pass strText=vbNullString
  'MsgBox StringResourceModify(sResExeFilePath, 102, vbNullString)

  Dim st() As StringTable, sMsg As String, i As Long
  st = StringResourceList(sResExeFilePath)
  For i = 0 To UBound(st)
    sMsg = sMsg & st(i).id & " : " & st(i).Text & vbCrLf
  Next
  MsgBox sMsg, , "List of string items"

  DisplayBitmapRes Picture1.hdc, sResExeFilePath, 101
  DisplayStringRes sResExeFilePath, 101
  Me.Caption = "BMP Resource from : " & sResExeFilePath
End Sub

Private Sub Form_Load()
  Command1.Caption = "Modify Resource Demo"
End Sub

Related links

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/resource_86yb.asp

ID: Q196774 SAMPLE:Stablupd.EXE Manipulate String Resources in an 
Executable[win32sdk]
http://support.microsoft.com/support/kb/articles/q196/7/74.asp

ID: Q139030 HOWTO: Edit Resources in Executables with Visual C++ [visualc]
http://support.microsoft.com/support/kb/articles/q139/0/30.asp


Submitted By : Nayan Patel  (Member Since : 5/26/2004 12:23:06 PM)

Job Description : He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting.
View all (893) submissions by this author  (Birth Date : 7/14/1981 )


Home   |  Comment   |  Contact Us   |  Privacy Policy   |  Terms & Conditions   |  BlogsZappySys

© 2008 BinaryWorld LLC. All rights reserved.