Results 1 to 5 of 5

Thread: Mixed Language Programming - Some assembly required =P

  1. #1

    Thread Starter
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Mixed Language Programming - Some assembly required =P

    I posted months ago that if I found the time I would write a tutorial on using asm and visual basic in mixed language programming. So it took me a while to get around to it but better late then never. As you may have noticed I'm posting this in the vb6 section, though this method will work in the .net versions as well. I still haven't jumped on the .net ship because I'm waiting on vs.net version 5. Mainly due to much needed upgrades for C++.

    If you have ever thought about writing a program that requires speed or needs access to low level hardware, most visual basic programmers think again. The reason is simple, you simply cannot do that in visual basic. No matter how good of a visual basic programmer you are, and how well you have optimized an algorithm, it's slow just because its done in visual basic. Those who do try to do this anyway, end up creating slow and sometimes very buggy code because they try to wield visual basic in a way that cannot be done. A good example of this is direct x sound plugins that some people attempt to create. I talked to a friend of mine just last night, whom was trying to con me into creating some plugins. He said that some of those plugins are done in visual basic and he can simply load them into a program and his processor usage goes up 60% (And he has a fast computer).

    When you create a program of this nature, you have two choices.
    1.You do this program in another language like C++.
    2.You use visual basic and do the critical code in another language and call it from visual basic.

    Now if you want to go with #1 that is fine, but I'm sure your going to miss visual basic when you are designing the GUI (I know I do). One thing I wish Microsoft would do is give C++ programmers the ability to design an interface like that. However at the same time allow c++ programmers see the skeleton that creates it, allowing us to tweak it or add to it. I think productivity in C++ would go up 10 fold at least!

    Now if we go the #2 way, we can speed up development quite a bit. After all we can do just about all the coding in visual basic, we just have the need to speed up certain parts that are critical to our application. So in a nutshell we decide to use mixed language programming. The idea of mixed language programming comes from people who want to go route #2. In fact Microsoft has been known to go route #2 with their operating systems. They code mostly in C and do some of the critical stuff in assembly. This allows Microsoft to create operating systems so complex as they do today. This wouldn't be possible if they did it all in assembly and would be as fast if they did it all in C.

    I've already written one tutorial on how to use mixed language programming with c++ and visual basic, this one is going to show you how to do it with assembly.

    Assembly language is a low level language that has a 1 to 1 correspondence with machine language. That means that every instruction you create in asm will correspond to an instruction in machine language. When you do your first hello world in assembly, you will be stunned about how much work is required to do something so simple. That is pretty much what we are going to accomplish with this tutorial, with the exception that we are going to use visual basic to create our front end. This way you will know how to port high speed algorithms in asm into your visual basic projects.

    One thing your gong to need of course is an assembler. I highly recommend MASM32, which you can download for free at www.masm32.com. This assembler makes it easier for us to do what we are going to do today, create win32 dlls. Which is what we have to create if we are going to be able to call this from visual basic. It has many built in features and so fort that make working with the api from asm, and the like very easy. This allows us to create the dll itself from a higher level perspective and worry about the details of the functions that it exports in a low level detail.

    There is also many sites out there that deal in working with assembly:
    http://www.nuvisionmiami.com/kip/asm.htm
    http://win32assembly.online.fr/tutorials.html

    Now after you have masm32 downloaded, lets create our first dll file. Open up the masm32 editor then go code/Create Dll from the menu. As you can see, they nicely include a template for us which saves us time from having to do that same **** over and over again with each new dll we create. I suppose I should still explain a few things:

    .486 – this directive tells what processor family we are going to be programming for. The bare minimal processor will be the 486. I should also point out that the code we run will work on both amd and intel as they both use x86.

    .model flat, stdcall – This directive tells what kind of memory model we are going to use. Windows uses the flat memory model. The stdcall is what type of calling convention we are going to use, which deals with function names and how the parameters are passed and of course who gets the fun of cleaning up the stack. Visual basic uses stdcall so we are going to leave that alone. However in different languages, you may need to change that. Some use the c calling convention and others the PASCAL calling convention.

    Option casemap :none – This simply tells the assembler to make things case sensitive.

    On down the code we see libraries and include files. This is basically to give our asm program access to the win32 api.

    Then we come to this curious looking directive:

    data?
    hInstance dd?

    Data? Is a directive we use for uninitialized data. IE: Data that will be decided at runtime. Then hInstance dd is our variable which we declare to be of size double word (Would be a long in visual basic, a 32 bit number).

    Code:
     LibMain proc instance:DWORD,reason:DWORD,unused:DWORD 
    
        .if reason == DLL_PROCESS_ATTACH
          push instance
          pop hInstance
          mov eax, TRUE
    
        .elseif reason == DLL_PROCESS_DETACH
    
        .elseif reason == DLL_THREAD_ATTACH
    
        .elseif reason == DLL_THREAD_DETACH
    
        .endif
    
        ret
    
    LibMain endp
    This is the dll entry point. Here you can put any cleanup or initialization code that your dll requires. As you can see by this function, we make use of some high level features to work with the dll, it makes creating the dll skeleton a lot easier.

    At the very bottom of the page you will see this: end LibMain. This should always be at the very bottom. It signals the end of our dll file. Between that and our main function is where our exported functions go (Functions that are going to be called from our visual basic program).

    So lets create a function to export:

    Code:
    TestFunction proc number1:DWORD, number2:dword
    
        mov eax, number1    ;Move number 1 into the eax register
        add eax, number2    ;Add the first number with the 2nd.
        ret                 ;Return the answer to visual basic.
    TestFunction endp
    As you can see we are creating a function called TestFunction. This function has two parameters which are DWORD, or a 32 bit number. Assembly doesn't have characters or integers or particular types of variables, in fact they're all the same as far as the assembler is concerned, the only difference being their size.

    Here is a list of some visual basic variables and how they correspond to assembly language variables:

    Visual basic – Assembly
    byte – BYTE
    boolean – WORD
    Integer – WORD
    Long – DWORD
    Short – DWORD
    String – DWORD Variable is passed by pointer.
    Char – BYTE

    The rest can always be looked up via MSDN.

    When you return a variable to visual basic, it is always done via eax. In fact that is pretty much universal that eax is used for returns.
    Now before we create the dll, we must add our TestFunction to the export list. Open up the projectnamehere.def file in notepad and you should see something that looks like this:

    LIBRARY mydll
    EXPORTS

    Just add TestFunction to the bottom of it so it looks like this:

    LIBRARY mydll
    EXPORTS
    TestFunction

    Safe the .def file and then compile your dll file. You can do this by going to project/run makeit.bat in your menu. If there is no errors then we can continue to setting up the call from visual basic =)



    Now to call this from visual basic, we simply do this:

    Code:
    Private Declare Function TestFunction Lib "c:\mydll.dll" (ByVal number1 As Long, ByVal number2 As Long) As Long
    
    Private Sub Command1_Click()
        MsgBox (Str(TestFunction(10, 10)))
    End Sub
    The only note here is that lib “c:\mydll.dll” should reflect the location and name of the dll on your hard drive.

    Output:
    Displays 20 in a message box.


    You may notice that the dll file created in this example is so small, on my machine it created a 2.5kb file, which is needless to say, very small!

    I've also included the files that I used in this example as an attachment. For those of you who are too lazy to copy and paste =P
    Attached Files Attached Files
    Last edited by Maven; Nov 28th, 2004 at 09:25 PM.
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

  2. #2

    Thread Starter
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Re: Mixed Language Programming - Some assembly required =P

    Update:
    If you ever want to pass arrays in visual basic, know that visual basic uses SAFEARRAY data types for all of their arrays. With the following exception: Strings. When you pass a string to a dll byval, it will only send a pointer to a null terminated string. However if you have an array of strings, it will be passed via method described below.

    Code:
          SAFEARRAYBOUND struct
                cElements	      	DWORD	?	      	  ; Number of Elements
                lLbound		      DWORD	?		        ; Lower Boundary
          SAFEARRAYBOUND ends
    
          OLE_SAFEARRAY struct
    	      cDims		            WORD	?		        ; Number of dimensions
    	      fFeatures	      	WORD	?		        ; Bitfield indicating attributes
    	      cbElements	      	DWORD	?		        ; size of an element of the array
       	      cLocks		      DWORD	?		        ; lock counter 0=Locked
    	      pvData		      DWORD	?		        ; Pointer to data
    	      rgsabound	            SAFEARRAYBOUND	<>	  ; Contains info for dimensions
          OLE_SAFEARRAY ends
    small example showing how to reference the structure:

    Code:
    testfunction proc myArray:DWORD
    mov eax, myArray
    mov edx, [eax]       ;EDX now has our safearray.
    
    'Assign 1st value to eax.
    mov eax, (OLE_SAFEARRAY ptr [edx]).pvData
    ret
    testfunction endp
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

  3. #3

    Thread Starter
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Re: Mixed Language Programming - Some assembly required =P

    One other thing off the top of my head...

    Visual basic does strings in unicode. Before a dll is called, visual basic creates a temp null terminated string and passes the pointer to that string to the dll. After the return of the dll, it converts it back into unicdoe. If you want to design a dll to work with unicode strings, you have to do a work around to avoid this conversion by visual basic. The only way I know of to do this is to assign a byte array to a string like this:

    bytearray() = mystring

    then pass the byte array to the dll. This will give you the unicode version of the string in the dll file. This is also a useful bit of information when working with a few unicode windows API's from visual basic.
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

  4. #4
    New Member
    Join Date
    Feb 2006
    Posts
    1

    Re: Mixed Language Programming - Some assembly required =P

    Thanks to Maven.
    Quote Originally Posted by Maven
    testfunction proc myArrayWORD
    mov eax, myArray
    mov edx, [eax] ;EDX now has our safearray.

    'Assign 1st value to eax.
    mov eax, (OLE_SAFEARRAY ptr [edx]).pvData
    ret
    testfunction endp
    How to call this testfunction in VB6? Can you give me an example?
    Last edited by Dreaminess; Feb 28th, 2006 at 03:03 AM.
    I'm from Vietnam
    I can't write English correctly

  5. #5

    Thread Starter
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Re: Mixed Language Programming - Some assembly required =P

    Quote Originally Posted by Dreaminess
    Thanks to Maven.


    How to call this testfunction in VB6? Can you give me an example?
    Private Sub Command1_Click()
    MsgBox (Str(TestFunction(10, 10)))
    End Sub

    all that is doing is calling the function which returns the number, converts it to a string for the messagebox.
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width