Author Topic: LinkRes2Exe fix (hack)  (Read 3402 times)

0 Members and 1 Guest are viewing this topic.

jcfuller

  • Guest
LinkRes2Exe fix (hack)
« on: July 25, 2019, 07:17:09 AM »
Charles,
  A bit of a hack but it worked with the WAVE test.
James

jcfuller

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #1 on: July 25, 2019, 08:03:23 AM »
Not there yet.
Does not work for WAVE with a numerical id instead of a string.
James

Charles Pegge

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #2 on: July 25, 2019, 09:18:44 AM »
Hi James,

I may have the solution for LinkRes2Exe:

original:
Code: [Select]
'----------------------------------------------------------
' Returns 0 if sz$ is an ordinal (numeric id)
' Returns a DWORD aligned length if a unicode name
'----------------------------------------------------------
FUNCTION IsUnicode(sz$) AS DWORD

   IF LOWORD(*(DWORD*)sz) = 0xFFFF THEN
      FUNCTION = 0
   END IF

   FUNCTION = dwAlign(2 + (2 * wcslen((LPCWSTR)sz)))
END FUNCTION

take out the dwalign call in isUnicode:
Code: [Select]
'----------------------------------------------------------
' Returns 0 if sz$ is an ordinal (numeric id)
' Returns a DWORD aligned length if a unicode name
'----------------------------------------------------------
FUNCTION IsUnicode(sz$) AS DWORD

   IF LOWORD(*(DWORD*)sz) = 0xFFFF THEN
      FUNCTION = 0
   END IF

   FUNCTION = 2 + (2 * wcslen((LPCWSTR)sz))
END FUNCTION

The resource names are not dwaligned.

PS I now have a working LinkRes in 32bit and 64bit o2 :)

jcfuller

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #3 on: July 25, 2019, 09:47:15 AM »
Charles,
  Hooray!
Sorry to let my OCD distract you. Now back to O2 building for you. :)

Did you rewrite in O2??

James

Brian Alvarez

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #4 on: July 25, 2019, 10:03:07 AM »
PS I now have a working LinkRes in 32bit and 64bit o2 :)

 ;D 8) :o :D

Charles Pegge

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #5 on: July 26, 2019, 01:06:37 AM »

For an integrated resource linker, you can detatch the console and parsing utilities. Then use LinkResources() directly.

LinkRes
Code: [Select]
'
'https://docs.microsoft.com/en-us/windows/win32/menurc/resource-file-formats


  $ Filename "LinkRes.exe"
  uses RTL64
  uses kernel
  %NoConsole
  uses console
  indexbase 1


type ResHead1
  dword DataSize
  dword HeaderSize
end type

type ResHead2
  dword DataVersion
  word  MemFlags
  word  LangId
  dword Version
  dword Charistics
end type



function RetResType (int ResType) as string
===========================================
  '
  select ResType

  case 0x0000 : return "NULL"
  case 0x0001 : return "Cursor"
  case 0x0002 : return "Bitmap"
  case 0x0003 : return "Icon"
  case 0x0004 : return "Menu"
  case 0x0005 : return "Dialog"
  case 0x0006 : return "String Table"
  case 0x0007 : return "Font Directory"
  case 0x0008 : return "Font"
  case 0x0009 : return "Accelerators Table"
  case 0x000A : return "RC Data (custom binary data)"
  case 0x000B : return "Message table"
  case 0x000C : return "Group Cursor"
  case 0x000E : return "Group Icon"
  case 0x0010 : return "Version Information"
  case 0x0011 : return "Dialog Include"
  case 0x0013 : return "Plug'n'Play"
  case 0x0014 : return "VXD"
  case 0x0015 : return "Animated Cursor"
  case 0x0018 : return "Manifest"
  case 0x2002 : return "Bitmap (new version)"
  case 0x2004 : return "Menu (new version)"
  case 0x2005 : return "Dialog (new version)"

  end select
  '
  return "Unknown"
end function


function RetMemFlags (int flags) as string
==========================================
  if flags = 0 then return "None"
  string MemFlags
  if flags and 0x10 then MemFlags="MOVEABLE"
  if flags and 0x20 then MemFlags+=" PURE"
  if flags and 0x40 then MemFlags+=" PRELOAD"
  if flags and 0x1000 then MemFlags+=" DISCARDABLE"
  return MemFlags
end function


function AddResources(string ResFile, TgtFile, int verbose=0) as int
====================================================================

  sys      hRes
  sys      ResBase
  sys      ResData
  sys      ResLen
  sys      ResPos
  sys      ResName
  sys      ResType
  wchar*   ResNameStr
  wchar*   ResTypeStr
  wchar*   unihead
  int      HeadOffset
  int      UniSize
  int      DataSpace
  int      Result
  ResHead1 *rh1
  ResHead2 *rh2
  string   ResBuf

  ResBuf=getfile(ResFile)
  if not ResBuf
    print "File not found: " ResFile cr
    return 1
  endif
  '
  hRes=BeginUpdateResource(TgtFile, 1)  ' File to add the resource to
  if not hRes
    print "BeginUpdateResource failed..."
    return 1
  endif
  '
  ResBase=strptr(ResBuf)
  ResLen = len(ResBuf)
  ResPos = 0
  int rhe1 = sizeof(rh1)
  int rhe2 = sizeof(rh2)
  while ResPos < ResLen
    @rh1=ResBase + ResPos
    UniSize = rh1.HeaderSize - rhe1
    Unisize=(Unisize + 3) and 0x7ffffffc 'dword align
    @Unihead=ResBase + ResPos + rhe1  'unicode/ordinal data then rh2
    @rh2 = @UniHead + UniSize - rhe2
    '
    ' Get the resource type
    word *w
    wchar st[64],sn[64]
    int i
    '
    @w=@unihead 'word overlay
    if w=0xffff
      ResType=w[2]
      st=RetResType(ResType)
      @ResTypeStr = @st
      HeadOffset=4 'dword
    else
      @ResTypeStr=@Unihead 'unicode
      ResType=@ResTypestr
      '
      'locate unicode null terminator
      i=0
      while w<>0
        i+=2 : @w+=2
      wend
      HeadOffset=i+2 'for start of ResName
    endif
    '
    ' Get the resource name
    word w at @unihead+HeadOffset
    if w=0xffff
      ResName = w[2]
      sn=str(ResName)
      @ResNameStr = @sn
    else
       @ResNameStr = @unihead+HeadOffset
       ResName    = @ResNameStr
    endif
    if Verbose
      string rt,rn
      rt=ResTypeStr
      rn=ResNameStr
      print "DataSize    = " rh1.DataSize cr
      print "HeaderSize  = " rh1.HeaderSize cr
      print "ResType     = " rt cr
      print "ResName     = " rn cr
      print "DataVersion = " rh2.DataVersion cr
      print "MemFlags    = " RetMemFlags(rh2.MemFlags) cr
      print "LangId      = " rh2.LangId cr
      print "Version     = " rh2.Version cr
      print "Charistics  = " rh2.Charistics cr
      print string(60, "-") cr
    endif
    '
    ResPos += rhe1 + UniSize 'ready for ResData
    ResData = ResBase+ResPos
    DataSpace = (rh1.DataSize+3) and 0x7ffffffc
    '
    ResPos+=DataSpace
    '
    if rh1.DataSize
      if not UpdateResourceW( hRes, ResType, ResName, rh2.LangId, ResData, rh1.DataSize)
        print "UpdateResource failed..."
        Result = 1
        exit while
      endif
    endif
  wend
 
  if not EndUpdateResource(hRes, Result)
    print "EndUpdateResource failed..." cr
    Result = 1
  endif
  return Result
end function




indexbase 1
int swd,lenw,ascw,ascn

sub SkipSpace(string*s, int*i)
==============================
  byte bb at strptr(s)
  do
    ascn=bb[i]
    select ascn
    case 0 : exit do
    'case 65 to 90 : ascn+=32 : exit do 'force lowercase
    case 33 to 255 : exit do
    end select
    i++
  loop
end sub


function GetWord(string*s, int*i) as string
===========================================
  byte bb at strptr(s)
  skipspace(s,i)
  swd=i
  do
    ascn=bb[i]
    select ascn
    case 0 to 32 : exit do
    case 34 : i=instr(i+1,s,chr(ascn))
      if i=0
        i=len(s)
      endif
    end select
    i++
  loop
  lenw=i-swd
  skipspace(s,i)
  if lenw>0
    return mid(s,swd,lenw)
  endif
end function


function CommandLineArgs() as string
====================================
  string s,command
  int i=1
  Command = (char*) GetCommandLine
  s=GetWord command,i 'step over command filepath\file
  SkipSpace command,i
  return mid Command, i
end function


function main() as int
======================
  int vb=0
  int i=1
  string s=lcase(CommandLineArgs())
  string resfile=getword(s,i)
  string tgtfile=getword(s,i)
  string opts=getword(s,i)
  '
  AttachConsole(-1) 'attach to console of parent process
  sys ho=GetStdHandle( STD_OUTPUT_HANDLE )
  if ho<>consout then consout=ho 'Windows10
  '
  if tgtfile
    if opts="-verbose"
      vb=1
    endif
    function = AddResources(resfile, tgtfile, vb)
  else
    print " LinkRes 2019" cr "  LinkRes  file.res  file.exe [-verbose]" cr
  endif
  FreeConsole
end function

return main()

Arnold

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #6 on: July 26, 2019, 01:59:14 AM »
Hi Charles,

I was distracted and have not followed this thread so far. You ported LinkRes2Exe.bas to Oxygenbasic? That is really brilliant. Can LinkRes be created as a 32-bit exe also? Is there a different behaviour of LinkRes2Exe and LinkRes? And what does LinkResources() mean? I have not yet tried LinkRes.o2bas.

Roland

Charles Pegge

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #7 on: July 26, 2019, 02:13:17 AM »
Hi Roland,

32 or 64 bit. The only reason for compiling is to use it as a command-line tool.

It behaves the same as LinkRes2exe, linking a res file to an exe or dll, though the source code is rather different.

Arnold

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #8 on: July 26, 2019, 04:19:21 AM »
Charles, will you provide both exe versions of LinkRes or is one version sufficient? GoRC also makes a distinction between /machine X86 (default) and /machine X64, but I am not sure if this really matters. As a precaution, I used two different versions of LinkRes and two different batch files in WinDynDialogs\ExeWithRes and \Multilingual. In any case, everything works fine with LinkRes and these two examples, 32-bit and 64-bit.

Charles Pegge

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #9 on: July 26, 2019, 04:51:51 AM »
I will provide LinkRes as a 64bit exe, but there's no difference apart from using RTL32/RTL64, and the functionality is the same.

Here is a minimal version which can be included in compilers or other tools.  It simply passes the required data from the res file to AddResource().

AddResources.inc
Code: [Select]
'
'https://docs.microsoft.com/en-us/windows/win32/menurc/resource-file-formats


type ResHead1
  dword DataSize
  dword HeaderSize
end type

type ResHead2
  dword DataVersion
  word  MemFlags
  word  LangId
  dword Version
  dword Characteristics
end type


extern lib "kernel32.dll"
  ! BeginUpdateResourceA
  ! UpdateResourceW
  ! EndUpdateResourceA
end extern


function AddResources(string ResFile, TgtFile) as int
=====================================================

  indexbase 1

  sys      hRes
  sys      ResBase
  sys      ResData
  sys      ResLen
  sys      ResPos
  sys      ResName
  sys      ResType
  wchar*   unihead
  int      HeadOffset
  int      UniSize
  int      DataSpace
  int      Result
  ResHead1 *rh1
  ResHead2 *rh2
  string   ResBuf

  ResBuf=getfile(ResFile)
  if not ResBuf
    '"File not found: " ResFile
    return 4
  endif
  '
  hRes=BeginUpdateResourceA(TgtFile, 1)  ' File to add the resource to
  if not hRes
    '"BeginUpdateResource failed..."
    return 2
  endif
  '
  ResBase=strptr(ResBuf)
  ResLen = len(ResBuf)
  ResPos = 0
  int rhe1 = sizeof(rh1)
  int rhe2 = sizeof(rh2)
  while ResPos < ResLen
    @rh1=ResBase + ResPos
    UniSize = rh1.HeaderSize - rhe1
    Unisize=(Unisize + 3) and 0x7ffffffc 'dword align
    @Unihead=ResBase + ResPos + rhe1  'unicode/ordinal data then rh2
    @rh2 = @UniHead + UniSize - rhe2
    '
    ' Get the resource type
    word *w
    int i
    '
    @w=@unihead 'word overlay
    if w=0xffff
      ResType=w[2]
      HeadOffset=4 'dword
    else
      ResType=@Unihead
      '
      'locate unicode null terminator
      i=0
      while w<>0
        i+=2 : @w+=2
      wend
      HeadOffset=i+2 'for start of ResName
    endif
    '
    ' Get the resource name
    word w at @unihead+HeadOffset
    if w=0xffff
      ResName = w[2]
    else
      ResName    = @unihead+HeadOffset
    endif
    '
    ResPos += rhe1 + UniSize 'ready for ResData
    ResData = ResBase+ResPos
    DataSpace = (rh1.DataSize+3) and 0x7ffffffc
    '
    ResPos+=DataSpace
    '
    if rh1.DataSize
      if not UpdateResourceW( hRes, ResType, ResName, rh2.LangId, ResData, rh1.DataSize)
        '"UpdateResource failed..."
        Result = 1
        exit while
      endif
    endif
  wend
 
  if not EndUpdateResourceA(hRes, Result)
    '"EndUpdateResource failed..." cr
    Result = 3
  endif
  return Result
end function

jcfuller

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #10 on: July 26, 2019, 07:46:32 AM »

Here is a minimal version which can be included in compilers or other tools.  It simply passes the required data from the res file to AddResource().

That would be a fine addition to co2 HINT HINT

James

Brian Alvarez

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #11 on: July 26, 2019, 05:12:34 PM »

Thanks Charles, it works very nice! :)

Brian Alvarez

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #12 on: July 26, 2019, 08:14:23 PM »
Charles, i noticed in your code that you use:

Code: [Select]
if w=0xffff
 This is normal and i use it often but i recall PowerBASIC interprets this as a signed integer: -1
while it requires &h0ffff for 65535.

 What is your opinion regarding this?

Charles Pegge

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #13 on: July 26, 2019, 11:35:26 PM »
That seems a bit fragile. It is only a bit pattern. o2 depends only on the type of variable being used. (In this case w is a word overlay for reading unicode character codes.)


jcfuller

  • Guest
Re: LinkRes2Exe fix (hack)
« Reply #14 on: July 27, 2019, 10:25:57 AM »
Charles,
  While waiting for you to add linkres to co2 :) I thought I would play around with it myself to become more familiar with O2.
I created a clone of co2.o2bas called brco2.o2bas and compiled it with co2 -c brco2.o2bas.
I then ran it from the command line and up pops the here's what I want window as it should.
But if I add a resource(version info and manifest) it no longer pops up the window.

James