PBDATA Modul (windows only)

Share your advanced PureBasic knowledge/code with the community.
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

PBDATA Modul (windows only)

Post by ts-soft »

With this module, native Windows resource file is provided.
The object code is provided without resource compiler.

Any file can be added.

To the use the "generated" *.res file, import it like: Import "MyRes.res" : EndImport
*mem = PBDATA::Get(ResID) will receive file into the memory. To find the size, use MemorySize(*mem)

Code: Select all

;======================================================================
; Module:          PBDATA
;
; Author:          Thomas (ts-soft) Schulz
; Date:            Jul 25, 2013
; Version:         1.0
; Target Compiler: PureBasic 5.2+
; Target OS:       windows only
; License:         Free, unrestricted, no warranty whatsoever
;                  Use at your own risk
;======================================================================

DeclareModule PBDATA
  Interface IPBDATA
    Free()                          ; close the resfile and releases the object.
    AddMem.i(ResID, *mem, size = 0) ; add the memory with resid to the resourcefile.
    AddFile.i(ResID, FileName.s)    ; load the file in to memory and add the memory with resid to the resourcefile.
  EndInterface
  
  Declare New(ResFile.s)            ; create object and open or create resfile. result is object.
  Declare Get(ResID, hModule = 0)   ; load the resource with resid in to memory. result is memoryaddress or 0 on error.
EndDeclareModule

Module PBDATA
  EnableExplicit
  
  Structure Class
    *vTable
    FF.i
  EndStructure
  
  Procedure New(ResFile.s)
    Protected *obj.Class
    
    *obj = AllocateMemory(SizeOf(Class))
    If *obj
      With *obj
        \vTable = ?vTable
        If LCase(GetExtensionPart(ResFile)) <> "res"
          ResFile + ".res"
        EndIf
        If FileSize(ResFile) > 0
          \FF = OpenFile(#PB_Any, ResFile)
          If \FF
            FileSeek(\FF, Lof(\FF))
            ProcedureReturn *obj
          Else
            Debug "PBDATA: Error open " + ResFile
            FreeMemory(*obj)
          EndIf
        Else
          \FF = CreateFile(#PB_Any, ResFile)
          If \FF
            WriteLong(\FF, 0)
            WriteLong(\FF, 32)
            WriteLong(\FF, 65535)
            WriteLong(\FF, 65535)
            WriteLong(\FF, 0)
            WriteLong(\FF, 0)
            WriteLong(\FF, 0)
            WriteLong(\FF, 0)
            ProcedureReturn *obj
          Else
            Debug "PBDATA: Error create " + ResFile
            FreeMemory(*obj)
          EndIf
        EndIf
      EndWith
    EndIf
    ProcedureReturn #False
  EndProcedure
  
  Procedure Free(*obj.Class)
    If *obj
      CloseFile(*obj\FF)
      FreeMemory(*obj)
    EndIf
  EndProcedure
  
  Procedure.i AddMem(*obj.Class, ResID, *mem, size = 0)
    Protected Mod
    
    If ResID < 1 Or ResID > 32767
      Debug "PBDATA: ResID out of range!"
      ProcedureReturn #False
    EndIf
    
    If *obj
      With *obj
        If *mem
          If size = 0 : size = MemorySize(*mem) : EndIf
  
          WriteLong(\FF, size)
          WriteLong(\FF, 44)
          WriteWord(\FF, 'P')
          WriteWord(\FF, 'B')
          WriteWord(\FF, 'D')
          WriteWord(\FF, 'A')
          WriteWord(\FF, 'T')
          WriteWord(\FF, 'A')
          WriteWord(\FF, 0)
          WriteWord(\FF, $FFFF)
          WriteWord(\FF, ResID)
          WriteLong(\FF, 0)
          WriteLong(\FF, 0)
          WriteLong(\FF, 0)
          WriteLong(\FF, 0)
          WriteWord(\FF, 0)
          WriteData(\FF, *mem, size)
          
          Mod = size % 4
          If Mod
            Select Mod
              Case 1 : WriteWord(\FF, 0) : WriteByte(\FF, 0)
              Case 2 : WriteWord(\FF, 0)
              Case 3 : WriteByte(\FF, 0)
            EndSelect
          EndIf
          ProcedureReturn #True
        EndIf
      EndWith
    EndIf
    ProcedureReturn #False
  EndProcedure
  
  Procedure.i AddFile(*obj.Class, ResID, FileName.s)
    Protected FF, *mem, size.q, result
    
    If ResID < 1 Or ResID > 32767
      Debug "PBDATA: ResID out of range!"
      ProcedureReturn #False
    EndIf
    
    If *obj
      FF = ReadFile(#PB_Any, FileName)
      If FF
        size = Lof(FF)
        If size
          *mem = AllocateMemory(size)
          If *mem
            ReadData(FF, *mem, size)
            CloseFile(FF)
            result = AddMem(*obj, ResID, *mem)
            FreeMemory(*mem)
            ProcedureReturn result
          Else
            Debug "PBDATA: can't allocate memory!"
            CloseFile(FF)
          EndIf
        Else
          CloseFile(FF)
        EndIf
      Else
        Debug "PBDATA: can't read " + FileName
      EndIf
    EndIf
    ProcedureReturn #False    
  EndProcedure
  
  Procedure.i Get(ResID, hModule = 0)
    Protected ResName.s, ResType.s = "PBDATA"
    Protected hFind, hLoad, hLock, hSize
    Protected *Mem
    
    If ResID < 1 Or ResID > 32767
      Debug "PBDATA: ResID out of range!"
      ProcedureReturn #False
    EndIf
    
    ResName = "#" + Str(ResID)
    If Not hModule : hModule = GetModuleHandle_(#Null) : EndIf

    hFind = FindResource_(hModule, ResName, @ResType)
    If hFind
      hLoad = LoadResource_(hModule, hFind)
      hSize = SizeofResource_(hModule, hFind)
      hLock = LockResource_(hLoad)
  
      *Mem = AllocateMemory(hSize)
      If *Mem
        CopyMemory(hLock, *Mem, hSize)
        FreeResource_(hLock)
        ProcedureReturn *Mem
      Else
        Debug "PBDATA: can't allocate memory!"
        FreeResource_(hLock)
      EndIf
    Else
      Debug "PBDATA: can't find resource " + ResName
    EndIf
    ProcedureReturn #False       
  EndProcedure
  
  DataSection
    vTable:
    Data.i @Free()
    Data.i @AddMem()
    Data.i @AddFile()
  EndDataSection
EndModule

CompilerIf #PB_Compiler_IsMainFile
  ; example 1
  EnableExplicit
  
  Define.PBDATA::IPBDATA mydata
  mydata = PBDATA::New(GetTemporaryDirectory() + "MyRes.res")
  If mydata
    mydata\AddFile(23, #PB_Compiler_Home + "purebasic.chm")
    mydata\Free()
  EndIf
  
  ; example 2
;   EnableExplicit
;   
;   Import "c:\Users\Thomas\AppData\Local\Temp\MyRes.res" : EndImport ; change to your path!
;   
;   Define *mem, FF
;   
;   *mem = PBDATA::Get(23)
;   If *mem
;     FF = CreateFile(#PB_Any, GetTemporaryDirectory() + "purebasic.chm")
;     If FF
;       WriteData(FF, *mem, MemorySize(*mem))
;       CloseFile(FF)
;       RunProgram(GetTemporaryDirectory() + "purebasic.chm")
;     EndIf
;     FreeMemory(*mem)
;   EndIf
  
CompilerEndIf
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image