Quantcast
Channel: VBForums - CodeBank - Visual Basic 6 and earlier
Viewing all articles
Browse latest Browse all 1448

How to statically link a LIB or OBJ file in VB6!

$
0
0
There is a kinda hacky way to do this actually! I realized that there's no way to statically link the code so that it can be called like a normal function, as VB6 IDE won't even try to compile something if the function is not specifically defined in the code (unlike C or C++ where it the compilation goes fine, and then the linker needs to figure out if that function exists in any external OBJ, LIB, or DLL files referenced in the linker's command line). In VB6 the IDE will immediately give an error in this situation when you click the "Make Project1.exe" menu item in the File menu. But there is a way to call DLL functions using Declare statements. I know that when using a declare statement, compilation will work fine, and then you will get a runtime error if the DLL isn't found when you try to run the program.

So I figured that since this delays the point at which the function needs to be available, maybe I could actually export the function from the EXE, as if it were a DLL (as both are PE files, so theoretically EXEs support an export table, just like DLLs), and then import it back in the same EXE for executing it (though technically it's not importing it the standard way via an import table, as it actually is creating pieces of code that call LoadLibrary and GetProcAddress internally followed by jumping to the address it gets from GetProcAddress, so even the linker doesn't need to process this, as it won't be creating an import table).

It turns out, that worked! For testing it, I used the same ASM function I used in https://www.vbforums.com/showthread....-a-VB6-program but this time tweaked the ASM code slightly so the resulting object file would contain the info needed to get the linker to first link the OBJ into the EXE, and then export the function from the EXE. Normally the linker needs an /EXPORT command line argument to export a function, but an object file can also contain an export directive so that the linker will automatically export the desired function. This latter technique is the one I used. That way, I only needed to add one thing to the VB6 linker command line, not 2 things, to get it to work. No need for the /EXPORT command line argument, just the path to the OBJ file that was generated from the NASM assembler.

Note that for this trick to work, you need to rename the VB6 linker to something else, and then create your own program called link.exe that lets you edit the command line before calling the actual linker (under its new name). This way when you click "Make Project1.exe" it actually calls your proxy first, which gives you control of the linker command line, before passing that now-edited command line to the actual linker.

Here's the code for my VB6 program.
Code:

'Import the function from the EXE file itself. This only works if the EXE exports it, which requires
'a proxy linker to replace the normal linker (with the normal linker renamed and called from the
'proxy), to give you access to the command line arguments. In this example you will need to make
'sure that it links shr.obj into the EXE file.
'Also the object file must have been made from some external source that supports the technique you
'wish to use. In this case, I used NASM to make a function called SHR which uses the x86 instruction
'shr. NASM assembled the assembly code into an object file, which (with a proxy linker to edit VB6's
'linker command line) will be linked into the EXE file, and since the assembly code stated that the
'function is exported, the resulting EXE file will export the function, and the below Declare will
'import it back into the same EXE. Not an ideal way to do static linking, but this trick is the only
'way to do it in VB6 using actual object files (should also work with LIBs that have multiple object
'files in them).

Private Declare Function SHR Lib "Project1.exe" (ByVal Value As Long, ByVal ShiftAmount As Byte) As Long


Private Sub Form_Load()
    Dim n As Long

    'Perform a test where it performs 32 different shifts (no shift, up to 31 bits shifted) on the hex value &hFFFFFFFF.
    'Note that with the static linking technique, this will ONLY work in the compiled EXE file, not in
    'the VB6 IDE, as static linking only occurs when generating the EXE file, not when running in the
    'VB6 IDE.
    For n = 0 To 31
        Print Hex$(SHR(&HFFFFFFFF, n))
    Next n
End Sub

Here's the ASM code I used.
Code:

BITS 32

GLOBAL SHR
EXPORT SHR

SECTION .text

SHR:
mov eax,[esp+4]
mov cl,[esp+8]
shr eax,cl
ret 8

The BITS 32 statement sets it to 32bit mode (NASM outputs 16bit code by default).
The GLOBAL SHR statement tells NASM to set a bit associated with the function SHR in the OBJ file, that tells any linker reading the OBJ file that the function can be used by other functions outside of that specific OBJ file (it's kinda like the Public keyword in VB6). The EXPORT SHR statement adds the function SHR to an export table in the OBJ file. Both the GLOBAL and EXPORT statements are needed to generate an OBJ file that when read by the VB6 linker the function will actually be added to the EXE file's export table. Same trick should work with a static LIB file, which is just a file that contains one or more OBJ files.

When all of this is done correctly, the function's machine code actually is added to the EXE file's code section directly (not contained in a hexadecimal string), that can then be executed in the same way that VB6 executes DLL functions, but since the code is in the EXE file itself, it doesn't require the presence of an external file like with an actual DLL file. This eliminates the need for using CallWindowProc or other function-calling functions, and also eliminates the need to have a dedicated function to convert hexadecimal string to raw bytes, and also eliminates the need to have a bunch of extra strings or byte array to hold the converted bytes. The code for the function instead is linked directly into the EXE file, along side all the code of the main program.

Please note that because this technique requires external software (the NASM assembler, and a proxy linker for VB6 that intercepts the command line for the VB6 linker), the code I have here is NOT usable as-is (unlike most of the code in the codebank). You can't just copy it all straight into your VB6 IDE and run it for immediate results. You'll need to first get a copy of NASM and assemble the ASM code in this post into an OBJ file, as well as write your own proxy linker program.

Note that when using NASM.exe, its default output is raw machine code (aka a "flat binary" file), not any kind of object file. You'll need to use the command line args "-f win32" to make it generate a 32bit Windows COFF object file as its output. That's what the VB6 linker expects for its input.

Yes, I tested everything in I wrote in this post, and it does work.

Viewing all articles
Browse latest Browse all 1448

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>