Just paste this code in Form1, and make sure Auto Redraw is enabled for the form. I've commented this code so you can see how it works at a glance.
When you run it, this is what you should see if it's working correctly.
Attachment 182347
The hexadecimal code in this program, I got by doing the following. I first used YASM to assemble this assembly code (but NASM would have worked as well).
I then used HxD hex editor to get the hexadecimal representations of the machine code bytes. This allowed me to embed the x86 machine code as a hexadecimal string directly inside my VB6 program's source code. This eliminates the need for my program to load a function from a separate file to execute it (whether a DLL or a raw file with with nothing but the raw machine code). It also eliminates the need to place a dummy function in the source code and then hack the exe in a hex editor after it's compiled to add the intended code into the compiled executable at the location where the dummy function was.
This allows adding functionality into a VB6 program that VB6 can't do directly (like the x86 SHR instruction which is a right shift that ignores the sign of the value, as if it was an unsigned value, even though VB6 considers it to be a signed value), without requiring external files, something I didn't think VB6 could previously do, because it doesn't support static linking of LIB and OBJ files exported from C or ASM compilers. Even if you intercept VB6's call to the linker link.exe and tell it to link a LIB or OBJ file, there's no way to write a program that makes use of such statically linked code, because the VB6 IDE gives an error if you try compile a program that calls a function that is not available at design-time (such as a function in the VB6 code itself or a DLL function that's declared). The technique I showed in this post provides a workaround for that, in effect giving you a way (albeit a complicated way) of statically linking a function into your program, by using hexadecimal encoded x86 instructions, instead of a LIB or OBJ file.
Obviously there's limits to this, as such code has no way to look at the import table of your EXE and call a Windows API function, so this x86 machine code cannot make any calls to functions in a DLL file. However, it does give you access to a host of useful functions found at the low level of assembly code, that you can't get in VB6 (unsigned bit shifts, unsigned 2-byte and 4-byte integer arithmetic, bit rotations, 2-argument version of atan, etc).
Code:
'Repurpose the CallWindowProcA function to call a generic function with the same prototype (4 Long args, and a Long retval).
Private Declare Function CallFunc Lib "user32.dll" Alias "CallWindowProcA" (ByVal FuncPtr As Long, ByVal Arg1 As Long, ByVal Arg2 As Long, ByVal Arg3 As Long, ByVal Arg4 As Long) As Long
Dim CodeSHR As String
Private Sub Form_Load()
Dim HexSHR As String
Dim n As Long
Dim val As Long
'Hexadecimal representation of raw x86 machine code for a function that performs SHR. This is a logical (not arithmetic) shift.
HexSHR = "8B4424048A4C2408D3E8C21000"
'Convert the hex string to raw bytes of executable code.
For n = 1 To Len(HexSHR) - 1 Step 2
CodeSHR = CodeSHR & ChrB("&h" & Mid(HexSHR, n, 2))
Next n
'Perform a test where it performs 32 different shifts (no shift, up to 31 bits shifted) on the hex value &hFFFFFFFF.
For n = 0 To 31
Print Hex$(SHR(&HFFFFFFFF, n))
Next n
End Sub
'This function calls the CallFunc function (which is actually just CallWindowProcA renamed), which calls the function stored in the CodeSHR byte string.
Private Function SHR(ByVal Value As Long, ByVal ShiftAmount As Byte) As Long
SHR = CallFunc(StrPtr(CodeSHR), Value, ShiftAmount, 0, 0)
End Function
Attachment 182347
The hexadecimal code in this program, I got by doing the following. I first used YASM to assemble this assembly code (but NASM would have worked as well).
Code:
BITS 32
mov eax,[esp+4]
mov cl,[esp+8]
shr eax,cl
ret 16
This allows adding functionality into a VB6 program that VB6 can't do directly (like the x86 SHR instruction which is a right shift that ignores the sign of the value, as if it was an unsigned value, even though VB6 considers it to be a signed value), without requiring external files, something I didn't think VB6 could previously do, because it doesn't support static linking of LIB and OBJ files exported from C or ASM compilers. Even if you intercept VB6's call to the linker link.exe and tell it to link a LIB or OBJ file, there's no way to write a program that makes use of such statically linked code, because the VB6 IDE gives an error if you try compile a program that calls a function that is not available at design-time (such as a function in the VB6 code itself or a DLL function that's declared). The technique I showed in this post provides a workaround for that, in effect giving you a way (albeit a complicated way) of statically linking a function into your program, by using hexadecimal encoded x86 instructions, instead of a LIB or OBJ file.
Obviously there's limits to this, as such code has no way to look at the import table of your EXE and call a Windows API function, so this x86 machine code cannot make any calls to functions in a DLL file. However, it does give you access to a host of useful functions found at the low level of assembly code, that you can't get in VB6 (unsigned bit shifts, unsigned 2-byte and 4-byte integer arithmetic, bit rotations, 2-argument version of atan, etc).