'
  'https://docs.microsoft.com/en-us/windows/win32/menurc/resource-file-format  /*
  'memory flags
  /*
  % MOVEABLE     0x0010
  % FIXED       ~MOVEABLE
  % PURE         0x0020
  % IMPURE      ~PURE
  % PRELOAD      0x0040
  % LOADONCALL  ~PRELOAD
  % DISCARDABLE  0x1000
  */

  /* Predefined resource types */
  % RT_NEWRESOURCE   0x2000
  % RT_ERROR         0x7fff
  % RT_CURSOR        1
  % RT_BITMAP        2
  % RT_ICON          3
  % RT_MENU          4
  % RT_DIALOG        5
  % RT_STRING        6
  % RT_FONTDIR       7
  % RT_FONT          8
  % RT_ACCELERATORS  9
  % RT_RCDATA        10
  % RT_MESSAGETABLE  11
  % RT_GROUP_CURSOR  12
  % RT_GROUP_ICON    14
  % RT_VERSION       16
  % RT_DLGINCLUDE    17
  % RT_VXD           20
  % RT_HTML          23
  % RT_NEWBITMAP     0x2002 '(RT_BITMAP|RT_NEWRESOURCE)
  % RT_NEWMENU       0x2004 '(RT_MENU|RT_NEWRESOURCE)
  % RT_NEWDIALOG     0x2005 '(RT_DIALOG|RT_NEWRESOURCE)


/*
  'menus 04
  =========

  typedef struct {
    WORD wVersion;     '00
    WORD cbHeaderSize; '00
  } MENUHEADER

  typedef struct {
    WORD    resInfo;  '01 80 
    szOrOrd menuText; 'wchar
  } NORMALMENUITEM

  typedef struct {
    DWORD   type;    '01 80 + MFT_ flags
    DWORD   state;   'MFS_ flags
    DWORD   id;      'pased to WM_COMMAND message
    WORD    resInfo; '01 80
    szOrOrd menuText;'wchars
  } POPUPMENUITEM;

  'from winuser.h
  'MFT_
  % MFT_STRING        0x00
  % MFT_BITMAP        0x04
  % MFT_MENUBARBREAK  0x20
  % MFT_MENUBREAK     0x40
  % MFT_OWNERDRAW     0x100
  % MFT_RADIOCHECK    0x200
  % MFT_SEPARATOR     0x800
  % MFT_RIGHTORDER    0x2000
  % MFT_RIGHTJUSTIFY  0x4000
  '
  'MFS_
  % GRAYED         0x0001   // 'GRAYED' keyword
  % INACTIVE       0x0002   // 'INACTIVE' keyword
  % BITMAP         0x0004   // 'BITMAP' keyword
  % OWNERDRAW      0x0100   // 'OWNERDRAW' keyword
  % CHECKED        0x0008   // 'CHECKED' keyword
  % POPUP          0x0010   // Used internally
  % MENUBARBREAK   0x0020   // 'MENUBARBREAK' keyword
  % MENUBREAK      0x0040   // 'MENUBREAK' keyword
  % ENDMENU        0x0080   // Used internally
  '
  % MFR_END   0x80 
  % MFR_POPUP 0x01
*/

/*
  accelerator table 09
  ====================

  typedef struct {
    word fFlags
    word wAnsi // or virtkey
    word wId
    word padding
  } ACCELTABLEENTRY

  'flags
  % FVIRTKEY  0x01
  % FNOINVERT 0x02
  % FSHIFT    0x04
  % FCONTROL  0x08
  % FALT      0x10
  % LASTENTRY 0x80

*/


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


  function findv(string*s,*wr) as int
  ===================================
  '
  'LOOKUP KEYWORD AND RETURN NUMBER
  '
  int a,e
  e=len(wr)
  a=idword(s,wr)
  if a
    return valat strptr(s)+a-1
  endif
  end function


  function BuildResources(string  rss, rcf, tgt) as int
  =====================================================
exit function
  #case capital
  '
  int     a,b,c
  int     i
  int id
  int     er
  string  wr
  wstring w1
  wstring ty
  wstring na
  wstring da
  wstring dm    'menu word string
   wstring nu=wchr(0)
  int dc
  string s=""
  sys   hres
  '
  hRes=BeginUpdateResourceA(tgt, 1)
  if not hRes
    '"BeginUpdateResource failed..."
    return GetLastError
  endif
  '
  if rss
    s=rss+cr
  endif
  if rcf
    s+=getfile rcf
  endif
  '
  'compile each resource
  '
  i=1
  do
    icas=1
    wr=bword(s,i)
    if lenw=0
      exit do
    endif
    a=findv "
    CURSOR       1
    BITMAP       2
    ICON         3
    MENU         4
    DIALOG       5
    STRING       6
    FONTDIR      7
    FONT         8
    ACCELERATORS 9
    RCDATA       10
    MESSAGETABLE 11
    GROUP_CURSOR 12
    GROUP_ICON   14
    VERSION      16
    DLGINCLUDE   17
    VXD          20
    HTML         23
    NEWBITMAP    0x2002
    NEWMENU      0x2004
    NEWDIALOG    0x2005
    ",wr
    if not a
      i=swd
      w1=pword(wr,i)
      continue do
    endif
    ty="#"+str(a)
    select a
      case 4 : gosub buildmenu
    end select
  loop
  '
  a=UpdateResourceW(
    hRes,   'handle
    ty,     'typename wchars
    na,     'pointer to name chars
    0x409,  '0x409 for US english
    da,     'pointer to data
    dc      'count of data bytes
  )
  if not a
    er=GetLastError()
  endif
  '
  if not EndUpdateResourceA(hRes, 0)
    '"EndUpdateResource failed..." cr
    er=GetLastError()
  endif
  return er
  '
  '

  buildmenu:
  ==========
  do
    icas=1
    wr=bword(s,i)
    if lenw=0
      exit do
    endif
    '
    'MFT_
    a=findv "
    {      0x01
    }      0x80
    BEGIN  0x01
    END    0x80
    STRING        0x00
    BITMAP        0x04
    POPUP         0x10
    MENUBARBREAK  0x20
    MENUBREAK     0x40
    OWNERDRAW     0x100
    RADIOCHECK    0x200
    SEPARATOR     0x800
    RIGHTORDER    0x2000
    RIGHTJUSTIFY  0x4000
    ",wr
    select a
    end select
    '
    'MFS_
    b=findv "
    GRAYED     0x03
    DISABLED   0x03
    INACTIVE   0x03
    CHECKED    0x08
    HILITE     0x80
    UNCHECKED  0x00
    UNHILITE   0x00
    DEFAULT    0x1000
    ",wr
   select b
   end select
   if nisxn
     icas=1
     dm=bword(s,i)
   else
     dm=""
   endif
   da=da+nu+wchr(a)+nu+wchr(b)+
   nu+   wchr(id)+wchr(1)+dm+nu
  loop
  ret
  '
  end function


  type Resource
    dword  DataSize;           // size of data without header
    dword  HeaderSize;         // Length of the additional header
    dword  otype '[Ordinal or name TYPE]     // type identifier, id or string
    dword  oname '[Ordinal or name NAME]     // name identifier, id or string
    dword  DataVersion;        // predefined resource data version
    word   MemoryFlags;        // state of the resource
    word   LanguageId;         // UNICODE support for NLS
    dword  Version;            // Version of the resource data
    dword  Characteristics;    // Characteristics of the data
  end type

  type ResHead1
    dword DataSize
    dword HeaderSize
  end type

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

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


  function AddReso(ResHead1*rh1, ResHead2*rh2) as int
  ===================================================
  if rh1.DataSize
    'eg: UpdateResourceW hr, L"#4",L"#1000",0X800,dat,cb
    'print "Restype: " restype "," resname "," rh2.langid "," rh1.datasize
    if not UpdateResourceW(
      hRes,        'handle
      ResType,     'pointer to typename chars
      ResName,     'pointer to name chars
      rh2.LangId,  '0x409 for US english
      ResData,     'pointer to data
      rh1.DataSize 'count of data bytes
      )
      '"UpdateResource failed..."
      Result=1
      return 0
    endif
  endif
  return 1
  end function


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

  indexbase 1

  ResBuf=getfile(ResFile)
  if not ResBuf
    ers="File not found: " ResFile cr
    return 1
  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 'roundup 4
    '
    ResPos+=DataSpace
    '
    if not AddReso(rh1,rh2)
      exit while
    endif
  wend
  '
  if not EndUpdateResourceA(hRes, Result)
    '"EndUpdateResource failed..." cr
    Result = 3
  endif
  return Result
  end function
