Welcome, Guest
You have to register before you can post on our site.

Username
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 136
» Latest member: Rob Wooding
» Forum threads: 137
» Forum posts: 1,075

Full Statistics

Latest Threads
GDI+ Gauges custom contro...
Forum: Programming
Last Post: Jules Marchildon
1 hour ago
» Replies: 4
» Views: 101
Next Gen Visual Designer ...
Forum: Programming
Last Post: Jules Marchildon
27.10.2026, 04:38
» Replies: 14
» Views: 1,147
Program that won't close
Forum: PowerBASIC for Windows
Last Post: Mike Doty
26.10.2026, 15:54
» Replies: 6
» Views: 299
EnableVisualStyles.bas
Forum: Source Code Library
Last Post: Stanley Durham
25.10.2026, 01:12
» Replies: 5
» Views: 271
PHP and PowerBasic
Forum: PowerBASIC for Windows
Last Post: Fim Wästberg
24.10.2026, 17:18
» Replies: 2
» Views: 192
Claude
Forum: PowerBASIC for Windows
Last Post: Stanley Durham
20.10.2026, 00:30
» Replies: 18
» Views: 2,437
LOOP remains active after...
Forum: Programming
Last Post: Dale Yarker
18.10.2026, 17:00
» Replies: 4
» Views: 385
trailing semicolon?
Forum: PowerBASIC for Windows
Last Post: Borje Hagsten
15.10.2026, 14:12
» Replies: 3
» Views: 395
Promoting PowerBASIC docu...
Forum: PowerBASIC Documentation
Last Post: Claudio DalZovo
13.10.2026, 17:18
» Replies: 6
» Views: 6,789
PowerBASIC Users...
Forum: This and that - friendly chat
Last Post: Marc Giao
11.10.2026, 04:04
» Replies: 2
» Views: 403

 
  How to run own code
Posted by: Juergen Kuehlwein - 12.04.2026, 14:08 - Forum: JKB (32/64 bit Compiler) - No Replies

My IDE makes extensive use of hot keys, type CTRL + H for a list of key combinations

In the IDE´s folder there is a file (list of available features.txt) listing all currently supported statements. Most statements are compatible to PB syntax

I´m not absolutely sure, if my implementation of macros works correct under all circumstances, the same applies to math functions and all kinds of expressions, especially with new data types like QWORD and SBYTE. I am sure there will be bugs, issues and problems i didn´t find yet!


Compiling the same code for 32 and 64 bit requires a special data type, which represents 32 bit in 32 bit and 64 bit in 64 bit: XWORD (unsigned) and XLONG (signed). Therefore all include files (i used José´s) must be prepared for this. Currently not all but about 2/3 have been translated and can be found in \Basic\Include_new.

64 bit code is much more picky about alignment, 64 bit code refuses to work, if structure alignment is not correct. This produces hard to find errors, and i´m not sure if all structures have been translated properly for 64 bit.

Inline assembler works as usual, i build ebp/rbp based stackframes and you can use PUSH and POP as usual, but in 64 bit code the stack pointer (rsp) must be 16 byte aligned before calls, otherwise you will experience all kinds of crashes. You may replace e/r by x for registers in order to write code, which compiles in 32 and 64 bit. Internally xax becomes eax in 32 bit and rax in 64 bit, this applies to all standard 32 bit registers (eax, ebx, ecx, edx, esi, edi, ebp, esp), obviously you cannot use r8 - r15 in 32 bit code.


In 32 bit code the constant %x32_code and in 64 bit code %x64_code are predefined, so you can build conditional compiling blocks like:

#ifdef %x64_code

... 64 bit code goes here (must be compilable)

#else

... 32 bit code goes here (must be compilable)

#endif


While PowerBASIC allows for (variable)names like "cx" or "si", which are valid register names, my implementation currently doesn´t. So you must use different names. ATM there are some more words (in addition to language keywords), which are forbidden. You will get an error message in such cases.


My object and COM implementation may need improvement, the focus was on being able to use COM services, which seems to work.Writing COM servers is possible but with some restrictions. Inheritance and multiple interfaces are not handled absolutely correct, i fear. There is nothing like #TLIB and "ME." (an object calling itself) doesn´t work yet.
I want better error reporting, in many places you will get a simple "syntax error". It is possible to have more specific messages and i plan to do that, but it is not on top of my priority list.


There are many ways of improving and optimizing my code, but for the moment the most important thing is making the "core" things stable.

Then will be the time to add more features, currently it supports, what i would call the "core" features of a BASIC language. Feel free to ask for "core" features i might have missed. But i won´t add more or less "special" things, before the core can be considered actually stable. At the current point of development i must thoroughly test, what i have in order to avoid changes in the core functionality later on. Code generation must cover different scenarios, the currently supported feature set covers all these scenarios in (hopefully) all it´s aspects. So it should be suited for testing and finding bugs i missed. Further development will then be a variation or implementation of the existing core of code.

E.g when passing arguments, such an argument can be: a literal, a constant, a variable, an array (as a whole, or as one single element), a structure (as a whole, or as one member of it), nested structures, a pointer, a resolved pointer, procedure returns, intrinsic functions (results from key words) and combinations and expressions of all of this. An argument can be passed "byref", "byval" and "bycopy". So there is a variety of possibilities, which must be taken care of.

The most simple code for own tests would be:

Code Select
Code:
#COMPILER JKB 32
#COMPILE EXE

FUNCTION MAIN

...

END FUNCTION


Now you can fill in the body of MAIN (for convenience PBMAIN is also possible) with declarations of variables and code using the syntax known form PB. You can add subs and functions as usual. You may add "#INCLUDE "Win32Api.inc" for access to predefined constants and the Windows API.

About 2/3 of José´s include files are already adapted to work in 64 bit Windows. There might still be issues though


"F9" will start the code generation and if this was successful, start the compiled executable. AV will often not be you friend here! You may add resources by "#RESOURCE "<resourcefilename>.res", but even adding a version control block and a manifest does not ensure smooth testing.

When there are syntax errors inside the BASIC code, these errors are shown in the IDE. In case of no error so far, the generated assembler code is passed to an assembler and linker, errors are shown in the IDE. Finally the created executable is run.

For debuging you can inspect final or intermediate results with "MSGBOX", use "STR$" or "HEX$" for numeric results, or you can make use of "ODS" or "ODX", which show debug output in a special viewer, which doesn´t block code flow like a message box.


Basically everything listed in features is allowed as syntax element. Expressions and block constructs have a maximum nesting level of 64.

The generated assembler code still has potential for optimizing, but (as already mentioned) first i want to get it working and then i want to make it smaller, faster, whatever...

The IDE will create a bunch of extra files mostly for debugging purposes, these will not be visible anymore in a final state.



Please don´t post in this thread, use the "Discussions" thread. More explanations will follow as needed.

Print this item

  Download and setup
Posted by: Juergen Kuehlwein - 12.04.2026, 13:51 - Forum: JKB (32/64 bit Compiler) - No Replies

Hi all,

Below are a link and instructions for a setup - have fun


whole package:  https://www.dropbox.com/scl/fi/tc6syg81r...pbwwe&dl=1
update package:  https://www.dropbox.com/scl/fi/cl6294npc...bwzsq&dl=1



The .zip file is about 40 MB and contains an updated version of my IDE and the complete tool chain necessary for the new "compiler". In fact working together with my IDE this is a complete compiler toolchain creating Windows executables (internally it is a code converter creating assembler code, which in turn is assembled to standard COFF .obj files and then linked to an execuatable). There is a linker (PoLink64.exe) included. A better choice would be Mircosoft´s linker (link.exe + a bunch of dlls), but this linker is not redistributable. It is included in a (free) community version of Visual C. You may download and install VC to have it installed on your machine. For using it you must specify this executable in Path Options Dialog in my IDE. A typical location for VC22 would be: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\Hostx86\x86\link.exe.

There might be problems with AV scanners, even Windows Defender sees some versions of JK-Basic.exe (the "compiler") as a potential threat, while virustotal sees no problem. In Windows 11 .exe files might not run, because there is no digital signature. The IDE itself (jk-ide.exe) and the "compiler" (jk-basic.exe) are not digitally signed, and newly created executables will have no digital signature, except you can digitally sign them yourself (the IDE can do that, if you have a certificate).

As usual you can expand the package to a directory of your choice, it is path independent. I recommend a new location, if you already use my IDE. This version is still experimental, so in order not to destroy your work with an existing install, don´t just unpack this over it. Please don´t select a path way down in your folder tree, because there still is a limit in length for paths, which could come into play, if your install path is too long.


When expanding Windows defender (or other AV) might block or quarantine some of the files, so be sure you got them all. In Windows 10 and below it is sufficient to add the "root" directory of this package to the AV´s exception list. I recommend doing this, because to my experience every now and then AV will "butt in" and produce all kinds of strange errors. Sometimes it can be really hard to get such false positives out of quaratine and get it to work again. The package doesn´t contain any dangerous or malicious things. Fell free to re-check with virustotal.

Currently the tool chain only works with my IDE (jk-ide.exe), so you must be or make yourself familiar with it. There is a quite comprehensive help file (menu -> help\JK-IDE Help)


For a start i would like you to do the following things:

- download (full package, the "update package" is for updates, which requires only a subset of files to be replaced)

- unzip

- run jk-ide.exe (you maybe will be asked to specify a path for the PB compiler and for an include file set, please fill in the necessary paths and press "Apply". This happens only, if the IDE cannot find these paths itself)

- the IDE will do some internal setup work, don´t worry, this is expected. It will tell you, when it is finished.

- open "File" menu, select "New As" and "JKB", name and save this source file wherever you want, press "F9". Congratulations, you should have compiled your first 64 bit executable with JKB



Please tell me, if this doesn´t work as described in "Discussions" thread. Don´t post in this thread!

Print this item

  A new sub-forum for Juergen Kuehlwein's JKB (32/64 bit Compiler)
Posted by: Albert Richheimer - 12.04.2026, 07:36 - Forum: JKB (32/64 bit Compiler) - Replies (1)

Welcome to the new sub-forum for Juergen Kuehlwein's JKB. Juergen is going public with his new JKB (32/64 bit Compiler). Please follow the usual PUMP rules for posting in this area.

Cheers,
Albert (PUMP admin)

Print this item

  How many "1" bits /Is Number a Power of 2
Posted by: Dale Yarker - 16.03.2026, 11:54 - Forum: Source Code Library - No Replies

Code:
'The FASTPROCs here are for both PBWin 10 and PBCC 6.
'For older PB versions change FASTPROC to FUNCTION.
'The demo (in PBMAIN below) would need significant change to compile in older
'versions of PB.
#compile exe
#dim all
#if %def(%pb_cc32) 'ignore this in PBWin
  #console off     'no unneeded in PBCC
#endif
'
'#### Please start thread in Programming for comments/questions. ####
'
'I want a solitare game that was not in old PB formum Source Code.
'Do it myself.
'That requires shuffling cards. Instead of repeating shuffle code for other
'games make a DLL.
'Shuffling requires PRNG(s), and seeds for PRNDs. They are useful for more
'than just card game, so another DLL.
'One of the PRNG algorithms fails if seed is a power of 2.
'
'(PRNG is pseudo Random Number Generator, NUT is Number Under Test.)
'
'How many bits are "1"?
''Simple use of the assembly POPCNT needed in power of 2 procs.
''is DWORD/LONG agnostic
fastproc BitCount(byval NUT as long) as long
  ! popcnt eax, NUT
  ! mov NUT, eax
end fastproc = NUT
'
'Is a DWORD number a power of 2?
fastproc IsPowerOf2Dw (byval NUT as long) as long
  ! mov ebx, NUT        'so not to modify NUT
  ! and ebx, &h00000001 'without this 1 returns as PO2
  !  jz IsEven
  ! jmp NotPO2
  IsEven:
  ! popcnt ebx, NUT
  ! cmp ebx, 1
  ! jne NotPO2
  ! mov NUT, -1
  ! jmp Done
  NotPO2:          '   -4 -8
  ! mov NUT, 0
  Done:
end fastproc = NUT
'
'Is a LONG number a power of 2?
''(Second procedure because in DWORD bit 31 is MSB of the number, while
'''in a LONG it is the sign flag and remaining bits are in 2s compliment
'''format.)
fastproc IsPowerOf2Lg (byval NUT as long) as long
  'check if NUT is negative
  !  bt NUT, 31
  ! jc NotPO2
  ! mov ebx, NUT
  ! and ebx, &00000001
  !  jz IsEven
  ! jmp NotPO2
  IsEven:
  ! popcnt ebx, NUT
  ! cmp ebx, 1
  ! jne NotPO2
  ! mov NUT, -1
  ! jmp Done
  NotPO2:
  ! mov NUT, 0
  Done:
end fastproc = NUT
'
'###############################################################################
function pbmain () as long
  local hTWin, NumD as dword
  local NumL, Retrn as long
  txt.window("BitCount, IsPowerOf2Dw and IsPowerOf2Lg"$$, 75, 50, 27, 40) _
                                                                        to hTWin
  '
  txt.color = %rgb_blue : txt.print "BitCount" : txt.color = %rgb_black
  NumL = 1 : Retrn = BitCount(NumL) : gosub PrintCount
  NumL = 2 : Retrn = BitCount(NumL) : gosub PrintCount
  NumL = 15 : Retrn = BitCount(NumL) : gosub PrintCount
  NumL = &h80050006 : Retrn = BitCount(NumL) : gosub PrintCount
  '
  txt.print : txt.color = %rgb_blue
  txt.print "Is DWORD a power of 2?"$$ : txt.color = %rgb_black
  NumD = 1 : Retrn = IsPowerOf2Dw(NumD) : gosub PrintDwd
  NumD = 4 : Retrn = IsPowerOf2Dw(NumD) : gosub PrintDwd
  NumD = 5 : Retrn = IsPowerOf2Dw(NumD) : gosub PrintDwd
  NumD = 4294967294 : Retrn = IsPowerOf2Dw(NumD) : gosub PrintDwd
  '
  txt.print  : txt.color = %rgb_blue
  txt.print "Is LONG a power of 2?"$$ : txt.color = %rgb_black
  NumL = 1 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = -1 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = 8 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = -8 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = 128 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = -128 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = 1024 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = -1024 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = 1026 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  NumL = -11026 : Retrn = IsPowerOf2Lg(NumL) : gosub PrintLng
  '
  txt.print
  txt.color = %rgb_green
  txt.print "Any key to close."$$
  txt.waitkey$
  exit function
  PrintCount:
    txt.print dec$(NumL) + " has " + dec$(Retrn) + " ""1"" bits."
  return
  PrintDwd:
    txt.print dec$(NumD);
    if Retrn then
      txt.print " is"$$
    else
      txt.print " is not"$$
    end if
  return
  PrintLng:
    txt.print dec$(NumL);
    if Retrn then
      txt.print " is"$$
    else
      txt.print " is not"$$
    end if
  return
end function
'#### Please start thread in Programming for comments/questions. ####

Print this item

  Notepad++ hacked
Posted by: Stanley Durham - 03.02.2026, 03:36 - Forum: This and that - friendly chat - Replies (4)

Chinese Hackers Remote Executed Code Via Notepad++ for 6 Months
_______________________________________________________

Please do not post any Youtube links (and others) without comment.

Thank you
Albert (PUMP admin)

Print this item

  Add "Board Statistics"
Posted by: Eros Olmi - 28.01.2026, 19:28 - Forum: Suggestions and discussion about PUMP - Replies (3)

If possible, it would be nice to have "Board Statistics" box in the bottom of the forum like in official MyBB forum

Print this item

  PB Hex Viewer
Posted by: Eros Olmi - 27.01.2026, 23:07 - Forum: Source Code Library - Replies (7)

Ciao,

I've attached a project I was working some time ago where I experimented AI (OpenAI ChatGPT and Google Gemini together) to code with some help ... well ... a lot of help.

It's a classic visual HEX viewer control able to show some memory buffer.
Clicking on the left hidden panel there are some options to change viewer

Attached 100% 10.4 PowerBasic source code and executable.
Do whatever with the sources.

Hope it can help someone.

Ciao
Eros



Attached Files Thumbnail(s)
       

.bas   HexControl_v0.4.1.bas (Size: 102 KB / Downloads: 21)
.zip   HexControl_v0.4.1.EXE.zip (Size: 28.48 KB / Downloads: 8)
Print this item

  Making text unreadable, 1 sample code works, 2 do not work
Posted by: Robert Alvarez - 22.01.2026, 19:32 - Forum: PowerBASIC for Windows - Replies (8)

Found three code samples in the internet to make text unreadable.
First one can read text and encrypt it and decrypt .
The second and third seems to encrypt it but decrypt does not work.

First sample code:

Code:
#COMPILE EXE
#INCLUDE "WIN32API.INC"
GLOBAL hDlg AS LONG

CALLBACK FUNCTION ENDPROG()
DIALOG END CBHNDL, 1
END FUNCTION

FUNCTION PBMAIN () AS LONG
$REGISTER NONE
LOCAL result, i AS LONG

'1. Basic Character Shift (Caesar Cipher Style)
OPEN "secret 1a.dat" FOR OUTPUT AS #1
text$ = "This is my secret message."
FOR i = 1 TO LEN(text$)
PRINT #1, CHR$(ASC(MID$(text$, i, 1)) + 5);
NEXT
CLOSE #1

OPEN "secret 1a.dat" FOR INPUT AS #1: LINE INPUT #1, text$
? text$ 'encryt
FOR i = 1 TO LEN(text$)
text1$=text1$+CHR$(ASC(MID$(text$, i, 1)) - 5)
NEXT
? text1$  'decreypt

DIALOG NEW 0, "TEST 1", ,, 200, 150, %WS_MINIMIZEBOX+%WS_SYSMENU, 0 TO hDlg
CONTROL ADD LABEL, hDlg, 100, "LABEL 1",80, 40, 60, 14,
CONTROL ADD BUTTON,hDlg, 202, "&Exit Program",100, 100,55, 14, CALL ENDPROG
CONTROL SET FOCUS  hDlg, 202
DIALOG SHOW MODAL  hDlg TO result
END FUNCTION

Second sample code:

Code:
#COMPILE EXE
#INCLUDE "WIN32API.INC"
GLOBAL hDlg AS LONG

CALLBACK FUNCTION ENDPROG()
DIALOG END CBHNDL, 1
END FUNCTION

FUNCTION PBMAIN () AS LONG
$REGISTER NONE
LOCAL result, i, key AS LONG

'2. XOR Encoding
OPEN "secret2a.dat" FOR OUTPUT AS #1
text$ = "This is my secret message."
key = 123  ' Simple numeric key

FOR i = 1 TO LEN(text$)
    PRINT #1, CHR$(ASC(MID$(text$, i, 1)) XOR key);
NEXT
CLOSE #1
'XOR is reversible — use the same key to decode.


OPEN "secret2a.dat" FOR INPUT AS #1
GET #1,1, ch$: ? ch$$
decoded$ = ""
key = 123
WHILE NOT EOF(1)
    INPUT #1, ch$  ' : ? ch$
    decoded$ = decoded$ + CHR$(ASC(ch$) XOR key)  ': ? decoded$
WEND
CLOSE #1
? decoded$

DIALOG NEW 0, "TEST 1", ,, 200, 150, %WS_MINIMIZEBOX+%WS_SYSMENU, 0 TO hDlg
CONTROL ADD LABEL, hDlg, 100, "LABEL 1",80, 40, 60, 14,
CONTROL ADD BUTTON,hDlg, 202, "&Exit Program",100, 100,55, 14, CALL ENDPROG
CONTROL SET FOCUS  hDlg, 202
DIALOG SHOW MODAL  hDlg TO result
END FUNCTION

Third sample code:
Code:
#COMPILE EXE
#INCLUDE "WIN32API.INC"
GLOBAL hDlg AS LONG

CALLBACK FUNCTION ENDPROG()
DIALOG END CBHNDL, 1
END FUNCTION

FUNCTION PBMAIN () AS LONG
$REGISTER NONE
LOCAL result, i, mask AS LONG

'3. Binary Write with Random Mask
RANDOMIZE TIMER
OPEN "secret 3.dat" FOR BINARY AS #1
text$ = "This is my secret message."
FOR i = 1 TO LEN(text$)
    mask = RND(255)
    PUT$ #1, CHR$(ASC(MID$(text$, i, 1)) XOR mask)
NEXT
CLOSE #1


OPEN "secret 3.dat" FOR BINARY AS #1
decoded$ = ""
DO UNTIL EOF(1)
    GET$ #1, 1, mask1$
    GET$ #1, 1, data1$
    decoded$ = decoded$ + CHR$(ASC(data1$) XOR ASC(mask1$))
LOOP
CLOSE #1
? decoded$

DIALOG NEW 0, "TEST 1", ,, 200, 150, %WS_MINIMIZEBOX+%WS_SYSMENU, 0 TO hDlg
CONTROL ADD LABEL, hDlg, 100, "LABEL 1",80, 40, 60, 14,
CONTROL ADD BUTTON,hDlg, 202, "&Exit Program",100, 100,55, 14, CALL ENDPROG
CONTROL SET FOCUS  hDlg, 202
DIALOG SHOW MODAL  hDlg TO result
END FUNCTION
 
How to fix?

Print this item

  PB DOS
Posted by: Brice Manuel - 19.01.2026, 09:48 - Forum: This and that - friendly chat - Replies (3)

I just recently ordered a new 386SX mini laptop system. Running DOS 6.22 and Windows 3.11. Lovely little beast. 40Mhz, 8MB RAM, and an IPS screen. It is capable of running Windows 95, but I do not want to at this time.

I am going to be working on some DOS & 16 bit Windows software.

PB DOS is still getting use from me.

Print this item

  Using #RESOURCE RCDATA to implement the missing #RESOURCE AVI
Posted by: George Bleck - 14.01.2026, 17:14 - Forum: Source Code Library - No Replies

I posted this on the new community run PB Users Forum: https://pbusers.org/forum/viewtopic.php?t=239
Sharing here as well as I think it is useful for those that might not have joined there yet.

============================


It always bothered me that PowerBASIC never implemented a #RESOURCE AVI metastatement. If you want to include an AVI for the animation control via #RESOURCE metastatements it's impossible as you cannot animate directly from RCDATA (or other resource sections available via the #RESOURCE metastatement). It can only be done from an AVI resource section (or from a supplied file path). Yes, you can compile the AVI into an AVI resource section using an RC file compiler and add it as a PBR (which still works but was technically deprecated) or RES, but "you cannot add any other #RESOURCE metastatements in your program" as per the PowerBASIC documentation.

What this code does is allow you to embed AVIs into your code using #RESOURCE RCDATA. After you compile your code to DLL or EXE you run this patcher by supplying the DLL/EXE file path on the command line (or via drag-and-drop). It proceeds to enumerate the AVIs and moves them to an AVI resource section using UpdateResource.

Be aware that you will need to repatch the DLL/EXE each time you re-compile your code.
As such, this could be included in a tool chain to always run after a compile.

Processing is written to a log (AVIRscPtch_Log.csv) in the directory the targeted module is located. To facilitate running in a toolchain it runs silently if no errors occur, but uses MESSAGEBOX to report any errors (in addition to the log).

Code:
' Compiles under PBWIN or PBCC without changes
#COMPILE EXE "AVIRscPtch.exe"
#DIM ALL

'----------------------------------------------------------------------------(')

%UNICODE = 1

'----------------------------------------------------------------------------(')

$DDQ = $DQ + $DQ

'----------------------------------------------------------------------------(')

#INCLUDE "Win32API.inc" ' Roca Headers III_107

'----------------------------------------------------------------------------(')

GLOBAL v_ghMod AS DWORD
GLOBAL v_ghUpd AS DWORD
GLOBAL v_gsExe AS STRING

'----------------------------------------------------------------------------(')

FUNCTION fn_sCSV(BYVAL v_sText AS WSTRING) AS STRING
  IF INSTR(v_sText, ANY CHR$(34, 44)) THEN
      REPLACE $DQ WITH $DDQ IN v_sText
      FUNCTION = $DQ + v_sText + $DQ
  ELSE
      FUNCTION = v_sText
  END IF
END FUNCTION

'----------------------------------------------------------------------------(')

FUNCTION fn_sTimestamp() AS WSTRING
  LOCAL v_uST AS SYSTEMTIME
  GETSYSTEMTIME v_uST
  FUNCTION = _
      FORMAT$(v_uST.wYear, "0000") + "-" + _
      FORMAT$(v_uST.wMonth, "00") + "-" + _
      FORMAT$(v_uST.wDay, "00") + " " + _
      FORMAT$(v_uST.wHour, "00") + ":" + _
      FORMAT$(v_uST.wMinute, "00") + ":" + _
      FORMAT$(v_uST.wSecond, "00") + "Z"
END FUNCTION

'----------------------------------------------------------------------------(')

FUNCTION fn_sGetErrorText(BYVAL v_lError AS LONG) AS WSTRING
  LOCAL v_lReturn AS LONG
  LOCAL v_szBuffer AS WSTRINGZ * 256
  IF v_lError = %ERROR_SUCCESS THEN EXIT FUNCTION
  v_lReturn = FORMATMESSAGE(%FORMAT_MESSAGE_FROM_SYSTEM, BYVAL 0&, v_lError, BYVAL 0&, v_szBuffer, SIZEOF(v_szBuffer), BYVAL 0&)
  IF v_lReturn > 0 THEN FUNCTION = RTRIM$(LEFT$(v_szBuffer, v_lReturn), ANY $CRLF)
END FUNCTION

'----------------------------------------------------------------------------(')

SUB sub_Log(BYVAL v_bError AS LONG, v_sText AS WSTRING)
  LOCAL v_hFile AS LONG
  LOCAL v_lError AS LONG
  LOCAL v_sLogPath AS WSTRING
  LOCAL v_sTimestamp AS WSTRING
  v_sTimestamp = fn_sTimestamp
  v_sLogPath = PATHNAME$(PATH, v_gsExe) + "\AVIRscPtch_Log.csv"
  TRY
      OPEN v_sLogPath FOR APPEND AS # v_hFile
      PRINT # v_hFile, v_sTimestamp + "," + fn_sCSV(v_sText)
      CLOSE # v_hFile
      IF v_bError THEN MESSAGEBOX %HWND_DESKTOP, "Error during patching:" + $LF + v_sText, EXE.NAMEX$, %MB_ICONEXCLAMATION
  CATCH
      v_lError = ERR
      MESSAGEBOX %HWND_DESKTOP, _
        "Could not record message to the log file." + $LF + $LF + _
        "Timestamp:" + $LF + v_sTimestamp + $LF + $LF + _
        "Log Path:" + $LF + v_sLogPath + $LF + $LF + _
        "Error:" + ERROR$(v_lError) + $LF + $LF + _
        "Msg:" + $LF + v_sText, _
        EXE.NAMEX$, %MB_ICONEXCLAMATION
      IF v_hFile THEN CLOSE # v_hFile
  END TRY
END SUB

'----------------------------------------------------------------------------(')

FUNCTION fn_bIsAVI(BYVAL v_pData AS DWORD, BYVAL v_cbData AS DWORD) AS LONG
  IF v_pData = 0 THEN sub_Log 0, "pdata = 0" : EXIT FUNCTION
  IF v_cbData < 12 THEN sub_Log 0, "cbData < 12" : EXIT FUNCTION
  IF PEEK$(v_pData, 4) <> "RIFF" THEN sub_Log 0, "Not a RIFF" : EXIT FUNCTION
  IF PEEK$(v_pData + 8, 4) <> "AVI " THEN sub_Log 0, "Not an AVI" : EXIT FUNCTION
  FUNCTION = %TRUE
END FUNCTION

'----------------------------------------------------------------------------(')

FUNCTION fn_lEnumLangProc( _
      BYVAL v_hModule AS DWORD, _
      BYVAL v_lpType AS DWORD, _
      BYVAL v_lpName AS DWORD, _
      BYVAL v_wLang AS WORD, _
      BYVAL v_lParam AS LONG) AS LONG
  LOCAL v_bOK AS LONG
  LOCAL v_cbData AS DWORD
  LOCAL v_hData AS DWORD
  LOCAL v_hRes AS DWORD
  LOCAL v_lError AS LONG
  LOCAL v_pData AS DWORD
  LOCAL v_wzTypeAVI AS WSTRINGZ * 4
  ' FindResourceEx
  v_hRes = FINDRESOURCEEX(v_hModule, BYVAL %RT_RCDATA, BYVAL v_lpName, v_wLang)
  v_lError = GETLASTERROR
  IF v_hRes = 0 THEN
      sub_Log 0, "Error calling FindResourceEx: " + fn_sGetErrorText(v_lError)
      FUNCTION = %TRUE
      EXIT FUNCTION
  END IF
  v_cbData = SIZEOFRESOURCE(v_hModule, v_hRes)
  v_hData = LOADRESOURCE(v_hModule, v_hRes)
  v_pData = LOCKRESOURCE(v_hData)
  IF fn_bIsAVI(v_pData, v_cbData) THEN
      v_wzTypeAVI = "AVI"
      ' UpdateResource - Copy resource to new resource type
      v_bOK = UPDATERESOURCE(v_ghUpd, BYVAL VARPTR(v_wzTypeAVI), BYVAL v_lpName, v_wLang, BYVAL v_pData, v_cbData)
      v_lError = GETLASTERROR
      IF v_bOK THEN
        ' UpdateResource - Remove resource from old resource type
        v_bOK = UPDATERESOURCE(v_ghUpd, BYVAL %RT_RCDATA, BYVAL v_lpName, v_wLang, BYVAL %NULL, 0)
        v_lError = GETLASTERROR
        IF v_bOK = %FALSE THEN sub_Log 1, "Error calling UpdateResource (delete old): " + fn_sGetErrorText(v_lError)
      ELSE
        sub_Log 1, "Error calling UpdateResource (copy to new): " + fn_sGetErrorText(v_lError)
      END IF
  END IF
  FUNCTION = %TRUE
END FUNCTION

'----------------------------------------------------------------------------(')

FUNCTION fn_lEnumNameProc( _
      BYVAL v_hModule AS DWORD, _
      BYVAL v_lpType AS DWORD, _
      BYVAL v_lpName AS DWORD, _
      BYVAL v_lParam AS LONG) AS LONG
  ENUMRESOURCELANGUAGES(v_hModule, BYVAL %RT_RCDATA, BYVAL v_lpName, CODEPTR(fn_lEnumLangProc), 0)
  FUNCTION = %TRUE
END FUNCTION

'----------------------------------------------------------------------------(')

FUNCTION PBMAIN() AS LONG
  LOCAL v_bOK AS LONG
  LOCAL v_lError AS LONG
  LOCAL v_sCmd AS STRING
  LOCAL v_wzExe AS WSTRINGZ * %MAX_PATH
  v_sCmd = TRIM$(COMMAND$, ANY CHR$(32, 34))
  IF LEN(v_sCmd) THEN
      v_gsExe = v_sCmd
  ELSE
      sub_Log 1, "Please supply a module (DLL/EXE) path to patch"
      EXIT FUNCTION
  END IF
  IF ISFILE(v_gsExe) = %FALSE THEN
      sub_Log 1, "Module (DLL/EXE) path does not exist"
      EXIT FUNCTION
  END IF
  v_wzExe = v_gsExe
  sub_Log 0, "Attemping to patch module: " + $DQ + v_gsExe + $DQ
  v_ghMod = LOADLIBRARYEX(BYVAL VARPTR(v_wzExe), BYVAL %NULL, %LOAD_LIBRARY_AS_DATAFILE)
  v_lError = GETLASTERROR
  IF v_ghMod = 0 THEN
      sub_Log 1, "Error loading module: " + fn_sGetErrorText(v_lError)
      EXIT FUNCTION
  END IF
  ' BeginUpdateResource
  v_ghUpd = BEGINUPDATERESOURCE(BYVAL VARPTR(v_wzExe), %FALSE)
  v_lError = GETLASTERROR
  IF v_ghUpd = 0 THEN
      sub_Log 1, "Error calling BeginUpdateResource: " + fn_sGetErrorText(v_lError)
      FREELIBRARY v_ghMod
      EXIT FUNCTION
  END IF
  ' EnumResourceNames
  v_bOK = ENUMRESOURCENAMES(v_ghMod, BYVAL %RT_RCDATA, CODEPTR(fn_lEnumNameProc), 0)
  v_lError = GETLASTERROR
  IF v_bOK = %FALSE THEN
      sub_Log 1, "Error calling EnumResourceNames: " + fn_sGetErrorText(v_lError)
      FREELIBRARY v_ghMod
      EXIT FUNCTION
  END IF
  ' Release the module
  FREELIBRARY v_ghMod
  ' EndUpdateResource
  v_bOK = ENDUPDATERESOURCE(v_ghUpd, %FALSE)
  v_lError = GETLASTERROR
  IF v_bOK = %FALSE THEN
      sub_Log 1, "Error calling EndUpdateResource: " + fn_sGetErrorText(v_lError)
      EXIT FUNCTION
  END IF
  sub_Log 0, "Module patched"
END FUNCTION

Print this item