Link to home
Start Free TrialLog in
Avatar of gonx
gonx

asked on

Need help on converting assembler to inline assembly

Im sort of a newbie on this.. need help on having this code in inline assembler for Visual C++ 6.0.. ive been trying to understand why the msdev hangs when it reaches INT 21h after i some of the 16 bit registers to 32 e.g eax,ebx,edi etc..

C++ code is as follows:

#include <stdio.h>
#include "drivesex.h"

main()
{
    int i;

    Drives_Exist();
    for (i = 0; i < 26; i++)
    {
        if (drives[i<<2] == DRIVEXISTS)
        {
            printf("%c: ",i+65);
            printf("%s ",drives[(i<<2)+1] == 0 ? "Removable" : "Fixed    ");

            switch (drives[(i<<2)+2])
            {
                case LOCALDRV :printf("Local  ");
                               break;
                case REMOTEDRV:printf("Remote ");
                               break;
                case SHAREDRV :printf("Shared ");
                               break;
            }

            switch (drives[(i<<2)+3])
            {
                case FLOPPY:printf("Floppy");
                            break;
                case HARD  :printf("Hard");
                            break;
                case RAM   :printf("RAM");
                            break;
                case SUBST :printf("Subst");
                            break;
                case CDROM :printf("CD-ROM");
                            break;
            }

            printf("\n");
        }
    }
}

the asm code is included separately as an ASM file:

; DRIVESEX.ASM - Drive existence detection      July 6th, 1994
; Code by       : Lee Hamel (hamell@cs.pdx.edu)
; Partial credit: Paul Schlyter
;
; Goes through drives A-Z and determines if they:
; 1) Exist
; 2) Are removable or fixed
; 3) Are local, remote, or shared
; 4) Are a floppy, hard, RAM, subst, or CD-ROM drive
;
; Callable from C as: void Drives_Exist(void);

.model small
.286

DRIVEEXIST      EQU     1

REMOVEDRV       EQU     0
FIXEDDRV        EQU     1

LOCALDRV        EQU     0
REMOTEDRV       EQU     1
SHAREDRV        EQU     2

FLOPPY          EQU     0
HARD            EQU     1
RAM             EQU     2
SUBST           EQU     3
CDROM           EQU     4

.data
PUBLIC  _drives
        _drives         db      26 dup(0,1,0,1)
        ; default to not exist, fixed, local, hard drive

.code

                        PUBLIC  _Drives_Exist
_Drives_Exist           PROC    NEAR
                pusha
                push    es

                mov     ah,19h
                int     21h             ; get start drive
                push    ax              ; save start drive

                mov     ax,40h
                mov     es,ax
                mov     bh,es:[10h]     ; 40:10h is # of floppies-1
                shr     bh,6
                inc     bh              ; # of actual floppy drives
                mov     bl,1
                mov     di,offset _drives
nextchkfloppy:  mov     ax,4409h        ; check if drive exists
                int     21h
                jc      nextsetfloppy
                test    dh,10000000b    ; check if SUBST drive
                jz      chkfloppy
                dec     bh              ; dec actual drive count
                mov     byte ptr [di+3],SUBST
setfloppyexist: mov     byte ptr [di],DRIVEEXIST
                jmp     nextsetfloppy
chkfloppy:      dec     bh              ; dec actual drive count
                js      nextsetfloppy
                mov     byte ptr [di+1],REMOVEDRV
                mov     byte ptr [di+3],FLOPPY
                jmp     setfloppyexist
nextsetfloppy:  add     di,4
                inc     bl
                cmp     bl,2            ; if B then jump back
                je      nextchkfloppy

                mov     ch,24           ; loop 24 times (drives C - Z)
                mov     cl,3            ; start at C:
drivechkloop:   mov     ax,4409h        ; check if drive exists
                mov     bl,cl           ; set drive letter
                int     21h             ; 0 = default, 1 = A:, etc.
                jc      nextsetdrv
                mov     byte ptr [di],DRIVEEXIST
                mov     ax,4408h        ; check if removable
                int     21h
                mov     byte ptr [di+1],al      ; set REMOVABLE or FIXED
                mov     bx,dx
                mov     dl,dh
                shr     dl,7
                and     dh,00010000b
                shr     dh,4
                mov     byte ptr [di+2],dh      ; set REMOTE or LOCAL
                or      dl,dl                   ; if not SUBST, then jump
                jz      chkremote
                mov     byte ptr [di+3],SUBST
                jmp     nextsetdrv

chkremote:      cmp     dh,REMOTEDRV    ; if REMOTE, then check for CD ROM
                je      chkcdrom

                test    bh,00000010b    ; sharable?
                jz      drivenoshare
                mov     byte ptr [di+2],SHAREDRV
drivenoshare:   test    bl,00000010b    ; RAM drive?
                jnz     nextsetdrv
                mov     byte ptr [di+3],RAM
                jmp     nextsetdrv

chkcdrom:       push    cx
                mov     ax,1500h
                xor     bx,bx
                int     2fh
                pop     cx
                or      bx,bx           ; MSCDEX driver found?
                jz      nextsetdrv      ; if not, jump to next drive setup
                mov     ax,150bh
                dec     cl              ; 0=A:, etc.
                int     2fh
                inc     cl
                or      ax,ax
                jz      nextsetdrv      ; drive supported by MSCDEX?
                mov     byte ptr [di+3],CDROM

nextsetdrv:     add     di,4
                inc     cl
                dec     ch
                jnz     drivechkloop

                pop     dx
                mov     ah,0eh
                int     21h             ; reset start drive

                pop     es
                popa
                ret
_Drives_Exist           ENDP

                        END

Thanks.. i would be grateful to anyone who can answer..
Avatar of nietod
nietod

That code is 16 but code (true) assembly code.  You can't use it for 2 reasons.  first of all, it is 16 bit.  It uses 16 bit techniques that are not permitted in 32 bit programs and Vc produces 32 bit programs.   Second, that code is true MASM asembly code.  Only MASM (or other assembler) can assemble it.  VC's inline assembler is not able to handle many aspects of it,


Why do you want to use assembly anyways?   Why not just handle it all in C++?

>> ive been trying to understand why the msdev hangs when it reaches INT 21h
because that itnterrupt is for 16 bit programs.
INT 21h is used by MS-DOS programs to do interrupts to MS-DOS (system calls). In 32 bit programs you use Win32 API instead.

Drop INT 21h and replace all int 21h instructions with the proper Win32 function calls.

Also, the 16 bit instructions is probably not a good idea on a 32 bit machine. Yes, most of them can run on a 32 bit machine but they will be slow and clumsy compared to the 32 bit code which is supposed to run on that machine.

Also, isn't it better to use 32 bit registers etc and drop those silly 16 bit registers?

Or use the more inutitive 32 bit adressing modes compared to the silly 16 bit adressing modes.


Writing 32 bit code you can do stuff like:

mov eax,5
mov edx,some_arr[eax*4] // access some_arr[5]

etc etc...

You can use (almost) any register as index register and you can use scaling so that the index register is automatically multiplied by 1, 2, 4 or 8 corresponding to arrays of char, short, int/float or __int64/double.

So drop the 16 bit MASM code and rewrite the thing for Win32. That's my advice.

You CAN use MASM also for 32 bit code, MASM will generate 32 bit code for you, but it is troublesome and not worth the effort, writing C++ or C code and use inline assembly will do it better.

Also, the MASM file you gave really has too much code, you can turn that into C++ code with far fewer lines of code.

Also, the Win32 function to check for drives is much easier to use than the MS-DOS Int 21 interrupt for the same thing. The Win32 function can give you a lot more info and can also give you info on drives that don't have a drive letter. Remember that on newer systems such as WinNT/2000/XP you can have a hard disk or CD-ROM that doesn't have a drive letter. True enough, few people make use of that feature because lots of system software from microsoft isn't able to handle it properly (for example a CD-ROM that doesn't have drive letter won't autoplay, appearantly the autoplay feature bluntly assume that all drives have drive letter for some weird and unknown reason). However, such bugs may some day disappear and then people will start to make use of the fact - especially so when they start to use shared drives and they run out of drive letters to use - after all there are only 26 letters available.

The Win32 functions to ask for drives do not (at least not all of those functions) assume that a drive has a drive letter. They do assume that if you want to access the drive from Win32 that it has a path though, but that is a less strict requirement than that it must have a drive letter.

Welcome to the new world :-)

Alf
Avatar of gonx

ASKER

Thank you for replying neitod and Salte.  I've been trying to find some C/C++ codes to help me with this but i didn't think about using Win32 functions to help me..and yeah i'd definitely want to turn all of that MASM code to C++ would you guys know of a good tutorial anywhere to teach a newbie about Win32 API? I've been trying to search all over the net for these kinds of stuff for months.

Again thanks.
>> Also, the 16 bit instructions is probably not a good idea on a 32 bit machine
That is untrue.  don't you think 32 bit programs ever work with bytes and words?

>> You CAN use MASM also for 32 bit code, MASM will generate 32
Unfortunatley, you can't realistically write 32 bit windows program.  You can but it is extremely difficult because MS choose to not release the necessary 32 bi t libraries.  

>>  I've been trying to find some C/C++ codes to help me with this but i didn't
>> think about using Win32 functions to help me
We'll resorting to assembly language seems like an extreme solution!

Its unclear to me what operatiosn you need to perform.  But I can assure you that the win32 API provides equivalent operations for every single dos operation (int21) and 1000s more.

I suspect you want to look into functions like
GetDriveType
GetVolumeInformation()
GetLogicalDrives()
GetLogicalDriveStrings()

the additional informaiton under these entries in the VC help will lead you to dozens of more file functions as well



The Win32 API is probably best documented by Microsoft in the documentation that comes with MSVC and also with Borland C++ builder (yes, it provides microsofts own documentation for the Win32 part).

Just check the help menu or write a function name such as:

CreateFile() or CloseHandle() and you get the help file up, then you can search the index and whatever you want.

Alf

actually MASM should work, you just call user32.exe/kernel32.exe/gui32.exe directly, they are always available to any 32 bit process.

kernel32.exe has the function LoadLibrary which gives you access to any DLL you fancy.

Maybe have a little trouble setting up the interface to call the Win32 functions from those dlls from assembly but it's far from impossible. Essentially you just have to do manually what the C and C++ compilers does for you.

On the other hand, using C++ instead of assembly is far better solution so I think learning the Win32 API as called from C++ and C programs is a far better way to go though.

Alf
>> actually MASM should work, you just call user32.exe/kernel32.exe/gui32.exe directly
Can you imagine writting a "real" program that way?   Every Os call would have to be though explicit linking?   And how do you call LoadLibrary() and GetProcAddress()?    Yes it can be done.  I've done it.  But its too much work to be worth it.  And then consider the fact that you need to define all the OS constants and data structues that you use, because MS didn't release them and becuse h2inc doesn't support win32 stuff.

>> it's far from impossible.
That is why I said its unrealistic.
Agree with you, it's not impossible but it is not worth the trouble.

Write C++ or C.

Alf
Avatar of gonx

ASKER

if you don't mind me asking where did all you guys learn this stuff? but anyway i'll look into this Win32 API calls then i'll get back to you guys.

Thanks
Avatar of gonx

ASKER

.. i don't see a tutorial who to use GetLogicalDriveStrings() on MSDN almost all the good tutorials are on Visual Basic, C#..

:(

DWORD StrLen = GetLogicalDriveStrings(0,NULL);  // Find necessary length.
char *DriveString = new char[StrLen + 1];   // Allocate space with room for the NUL.

GetLogicalDriveStrings(StrLen,DriveString)  // Get the string.

delete [] DriveStrings;  // clean up.
Avatar of DanRollins
nietod,
I am watching YOU!  You are about 3 questions away from reachin ONE MILLION POINTS!.  This is just
   * Congratulations! *
in advance!

gonx,
try this... Go to this site:
    http://msdn.microsoft.com/default.asp
and in the upper left corner where it says "Search for" type in
   GetLogicalDriveStrings
and press Enter.  When I did this, the first two items were
1) the official documentation of rhis API function
2) a C++ Q&A article.  That article provides a linek to some C++ code for a short program named "ListDrives" (Figure 2).
... a little lower is an overview of Drive-related fns...
5. http://msdn.microsoft.com/library/en-us/fileio/base/volume_management_functions.asp

That is how to locate information about Win32 API functions.

-- Dan
Avatar of gonx

ASKER

i already went to the links Dan wrote so im now fixing up the source of ListDrives.. i hope to understand why its giving me a

LINK : fatal error LNK1117: syntax error in option "subsystem:ListDrives"

neitod, the code definitely looks simpler than the MFC code from MSDN. Ive seen some code like that from the other threads here but for the life of me i have to study the whole thing all over again.. do you have a complete listing of the snippet?
>>  am watching YOU!  You are about 3 questions away from reachin ONE MILLION POINTS!.
I thought it was like 600,000???


try a console program with

#include <windows.h>
#include <iostream>
using namespace std;

int main()
{
   DWORD StrLen = GetLogicalDriveStrings(0,NULL);  // Find necessary length.
   char *DriveString = new char[StrLen + 1];   // Allocate space with room for the NUL.

   GetLogicalDriveStrings(StrLen,DriveString)  // Get the string.
   cout << DriveString << endl;
   delete [] DriveString;  // clean up.
   return 0;
}  
Avatar of gonx

ASKER

neitod or anyone for that matter, just this last question then my points are yours..

how do you loop the program so it detects every drive?


TY.

The function returns ALL the drives.  You just have to extract them.    I can post a little _sample_ code.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>> thought it was like 600,000???
You have over 850,000 in C++ alone (you are the top expert in this TA) and another 145,000 in Windows Programming TA (you are #5 there).  Current total: 995,314
-- Dan
Avatar of gonx

ASKER

You guys could write a good book/tutorials on these things