I don't personally have any code to test the include and library file for MSVCRT but the library built OK so if anyone has some time to test these it would be most appreciated. I extracted the exports from the DLL in win2k, made them all PROTO C :VARARG and then started building the library. I had to remove a number of name conflixts which I have put at the top of the include file.
[attachment deleted by admin]
Hi Hutch,
Nice work :U
Here is my dll2inc tool converting DLL files to include and module definition files:
dll2inc msvcrt.dll
You get two files named msvcrt.inc and msvcrt.def
To build the import library with Pelle's librarian:
\masm32\bin\polib /OUT:msvcrt.lib \windows\system32\msvcrt.dll
msvcrt.lib with a size of 147.4 Kb on Win Xp Home Sp2
[attachment deleted by admin]
Vortex,
Compliments, its a nice tool you have created. What we need is for you to get all of these tools up on your website so they are easily obtained by anyone who needs them.
The next question is does anyone know what the reference material for msvcrt is and how do you get at it. I suspect it will be part of Visual C which is probably a copyright problem but there are over 700 functions that appear usable in it so if there is an easy way to do the reference material, it would make this scale of functionality easily available to a large number of people.
Hi Hutch,
What I found in MSDN:
Run-Time Library Reference
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/vcrefruntimelibraryreference.asp
An alternate for msvcrt.dll is crtdll.dll An example, the compiler Lcc-Win32 uses crtdll
It would be very nice to use msvcrt in MASM!
But there can be some problems with the "fake" prototypes (I mean, all are :VARARG) in my project. I would like to get the real ones, but they are scattered around in many .h files.
How to collect them and make .inc file? Or what is the best method to achieve them?
BTW, I have almost no experience with C/C++.
Hi MazeGen,
To get the real prototypes, you can convert the .h files manually:
int __cdecl printf(const char * restrict, ...);
printf PROTO C :DWORD,:VARARG
int __cdecl sprintf(char * restrict, const char * restrict, ...);
sprintf PROTO C :DWORD,:DWORD,:VARARG
int __cdecl puts(const char *);
puts PROTO C :DWORD
Pelle's free C compiler set provides all these header files and they are classified in two main groups. One group for the standard C functions and the other for Win32 API functions.
Probably, it would be interesting to code a tool automating the conversion process.
Hi Hutch,
Nowadays, I am working on my homepage. I will try to put it up at the weekend.
Hi Wortex,
Quote from: Vortex on January 21, 2005, 11:38:05 AM
To get the real prototypes, you can convert the .h files manually
Huh, it could be a lot of work - more than 700 functions...
Quote from: VortexProbably, it would be interesting to code a tool automating the conversion process.
There's no sort of h2inc for such files already?
IIRC MSVCRT.DLL is included with all recent versions of Windows. I'm not sure about CRTDLL.DLL.
There are also the Global Constants (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_global_constants.asp). I have not investigated many of the constants, but I have needed RAND_MAX and errno, and IIRC I got the value of errno by calling the name as a function.
BTW, the CRT rand function is much faster than nrandom (60 vs 87 clocks on my system).
Hi MazeGen,
I remember there was a h2inc tool but I am not sure if it can perform a correct conversion process. Maybe, it's better to code a new version.
msvcrt for XP ver 7.X, 316K, came with OS.
msvcrt for 2K ver 6.X, 281K, Updated from the OS distribution, but one did come with it. (289K)
I would hope that the differences reflect only OS implementation (KERNEL32.dll) and not functional ones. I wish had some extra time to check up on this further.
Then we would have a simular problem with windows.inc file versioning.
Regards, P1 :8)
Hi Vortex,
Quote from: Vortex on January 21, 2005, 06:30:07 PM
I remember there was a h2inc tool but I am not sure if it can perform a correct conversion process. Maybe, it's better to code a new version.
you're right, I just get last version of h2inc and it is old obsolete MS-DOS executable and can't be used in this way.
It would be nice to have new version, but my knowledge of this problematic is poor.
I realized how worth would be to use msvcrt library - a lot of very well known functions; tested miliard times; my native asm forum is almost dead, with this library I can ask questins also in C forum; etc. etc.
I'm ready to convert the prototypes manually, but I'm very busy nowadays, so it has to wait...
I had to comment out the following lines in MSVCRT.INC to avoid naming conflicts:
556 atol
604 isalpha
609 islower
613 isupper
673 strcat
I have now done some testing of the library and include file, after making the changes noted in my last post, and everything I tested seems to work OK. I think the math routines are probably the most useful components, and to use them reasonably you must be able to monitor errors, so I tested the _matherr and errno components. I think something needs to be done about getting the necessary constants and structures together in an include file. And I think it might prevent some confusion if a system of equates were implemented that would allow the CRT functions to be named as CRT functions, say with a "crt_" prefix.
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc
include \masm32\include\msvcrt.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib
includelib \masm32\lib\msvcrt.lib
include \masm32\macros\macros.asm
; _errno returns the address of the errno variable.
errno MACRO
invoke _errno
mov eax,[eax]
EXITM <eax>
ENDM
; Did not actually test this.
set_errno MACRO val
push eax
call _errno
mov DWORD PTR[eax], val
pop eax
ENDM
_matherr PROTO :DWORD
_exception STRUCT
extype DWORD ?
lpName DWORD ?
arg1 REAL8 ?
arg2 REAL8 ?
rval REAL8 ?
_exception ENDS
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
str1 db "MY OTHER BROTHER DARRYL",0
double dq 0
int_part dq 0
fract_part dq 0
except _exception <>
.code
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
invoke printf,chr$("%s",13,10), ADDR str1
invoke _strlwr, ADDR str1
invoke printf,chr$("%s",13,10), ADDR str1
invoke _strrev, ADDR str1
invoke printf,chr$("%s",13,10), ADDR str1
invoke _strrev, ADDR str1
invoke printf,chr$("%s",13,10), ADDR str1
invoke _strupr, ADDR str1
invoke printf,chr$("%s",13,10), ADDR str1
invoke strtok, ADDR str1, chr$(" ")
invoke printf,chr$("%s",13,10), eax
@@:
invoke strtok, NULL, chr$(" ")
test eax,eax
jz @F
invoke printf,chr$("%s",13,10), eax
jmp @B
@@:
fldpi
fstp double
invoke modf, double, ADDR int_part
; Return value is left on FPU stack.
fstp fract_part
invoke printf,chr$("%1.0f %f",13,10), int_part, fract_part
; MASM will not correctly encode a single invoke that calls
; the errno macro twice, so I had to split the following.
invoke printf, chr$("errno = %d",13,10), errno()
invoke printf, chr$("strerror = '%s'",13,10), FUNC(strerror, errno())
invoke __setusermatherr, ADDR _matherr
invoke log, FP8(-2.0)
invoke printf, chr$("errno = %d",13,10), errno()
invoke printf, chr$("strerror = '%s'",13,10), FUNC(strerror, errno())
invoke _open, chr$("c:\myotherbrotherdarryl"), 0
invoke printf, chr$("errno = %d",13,10), errno()
invoke printf, chr$("strerror = '%s'",13,10), FUNC(strerror, errno())
invoke printf,chr$(13,10,"Press any key to exit...")
@@:
call _kbhit
test eax, eax
jz @B
exit
_matherr proc lpExcept:DWORD
mov ebx, lpExcept
ASSUME ebx:PTR _exception
invoke printf, chr$("_matherr return:",13,10)
invoke printf, chr$(" exception type = %d",13,10), [ebx].extype
invoke printf, chr$(" function name = '%s'",13,10), [ebx].lpName
invoke printf, chr$(" arg1 = %f",13,10), [ebx].arg1
;invoke printf, chr$(" arg2 = %f",13,10), [ebx].arg2
invoke printf, chr$(" return value = %f",13,10), [ebx].rval
ASSUME ebx:NOTHING
mov eax, 0 ; return zero so errno will be set
ret
_matherr endp
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
struct _exception {
int type; /* exception type - see below */
char *name; /* name of function where error occured */
double arg1; /* first argument to function */
double arg2; /* second argument (if any) to function */
double retval; /* value to be returned by function */
} ;
/* Constant definitions for the exception type passed in the
_exception struct */
#define _DOMAIN 1 /* argument domain error */
#define _SING 2 /* argument singularity */
#define _OVERFLOW 3 /* overflow range error */
#define _UNDERFLOW 4 /* underflow range error */
#define _TLOSS 5 /* total loss of precision */
#define _PLOSS 6 /* partial loss of precision */
#define EDOM 33
#define ERANGE 34
#define _O_RDONLY 0x0000 /* open for reading only */
#define _O_WRONLY 0x0001 /* open for writing only */
#define _O_RDWR 0x0002 /* open for reading and writing */
#define _O_APPEND 0x0008 /* writes done at eof */
#define _O_CREAT 0x0100 /* create and open file */
#define _O_TRUNC 0x0200 /* open and truncate */
#define _O_EXCL 0x0400 /* open only if file doesn't already exist */
#define _S_IREAD 0000400 /* read permission, owner */
#define _S_IWRITE 0000200 /* write permission, owner */
MY OTHER BROTHER DARRYL
my other brother darryl
lyrrad rehtorb rehto ym
my other brother darryl
MY OTHER BROTHER DARRYL
MY
OTHER
BROTHER
DARRYL
3 0.141593
errno = 0
strerror = 'No error'
_matherr return:
exception type = 1
function name = 'log'
arg1 = -2.000000
return value = -1.#IND00
errno = 33
strerror = 'Domain error'
errno = 2
strerror = 'No such file or directory'
MichaelW,
Very nice work.
Paul
Vortex,
Didn't you already do this once? What is the difference between your include and library and this one of Hutch's?
Hi Greg,
My tool creates the include file form msvcrt.dll, plus Pelle's library manager creates an import library for this DLL
Here is what I found for msvcrt, it seems to contain the original function declarations:
http://uemake.szm.sk/freeware/msvcrt.zip
http://uemake.szm.sk/menu/links/compilers.htm
:eek
Great job, Vortex!
I wonder who is the author, because if is he Slovak (.sk), I can speak with him in my native language.
Now I'm happy I didn't convert it manually before :toothy
Cool. My msvcrt.dll is different than these, so attached is an XP SP1 .lib and .inc zip, maybe it is useful. I can't imagine there being new procedures in each version of msvcrt? Neat tool Vortex. Is there any Win32.hlp for msvcrt? We really need something like that. And http://uemake.szm.sk/ appears to be down.
msvcrt.dll v7.0.2600.1106: WinXP SP1, 315 KB (323,072 bytes)
msvcrt.lib, 142 KB (145,662 bytes)
Pelle's POLIB reported:
POLIB: warning: '_exit' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '__imp__exit' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '_strerror' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '__imp__strerror' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '_tolower' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '__imp__tolower' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '_toupper' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
POLIB: warning: '__imp__toupper' already defined in 'msvcrt.dll'; ignoring definition in 'msvcrt.dll'.
Removed from msvcrt.inc due to [apparent] naming conflicts:
abs PROTO C :VARARG
atol PROTO C :VARARG
div PROTO C :VARARG
exit PROTO C :VARARG
fabs PROTO C :VARARG
isalpha PROTO C :VARARG
islower PROTO C :VARARG
isupper PROTO C :VARARG
strcat PROTO C :VARARG
[attachment deleted by admin]
I think it is great we are helping each other, but the concern I have is that the proto's are not
correct. Does someone go back and fix these up ?
Hi Mark,
Here is uemake's zip file.
I posted the links for the msvcrt reference, you can check page 1 of this topic.
[attachment deleted by admin]
Quote from: MazeGen on January 21, 2005, 11:47:29 AM
Hi Wortex,
Quote from: Vortex on January 21, 2005, 11:38:05 AM
To get the real prototypes, you can convert the .h files manually
Huh, it could be a lot of work - more than 700 functions...
Quote from: VortexProbably, it would be interesting to code a tool automating the conversion process.
There's no sort of h2inc for such files already?
I Installed the Vc pp5 for Visual Studio, and in the masm reference mention about it. And I can't upload it because it's only license to vb owners,
:lol unless you show me a screenshot that yo own the v studio.
I have one doubt, what if I replace the ml 6.15 in the masm32; will it work fine? or it modifies something. And the ml it's included witha file called ml.err
Looks like it's a listing errors.
Don't delete the ml.err file, or ML error messages will be blank! (Some file-cleaning programs delete .err files...) I set mine to Read-Only.
Striker, yes but it looks like Uemaker's msvcrt.inc has all the prototypes correctly defined. :)
Aah Vortex, yes the MSDN page does have info, thanks.
Quote from: Mark Jones on March 06, 2005, 09:35:41 PM
Striker, yes but it looks like Uemaker's msvcrt.inc has all the prototypes correctly defined.
The ones that are there do seem to be correctly defined, but some are missing (_errno, _matherr, __setusermatherr, and possibly others). IMO, in the absence of easily accessible help, the prototypes should include the Microsoft-documented names for the parameters.
Here is a program I wrote to test using MSVCRT from MASM32, I used the include and lib Hutch posted. I was getting conflicts with MASM32.LIB so I used only MSVCRT and Win32 functions and cut and pasted the macros. I thought someone might find it interesting.
; Time64CRT.asm
.486
.model flat, stdcall
option casemap :none
include c:\masm32\include\windows.inc
include c:\masm32\include\kernel32.inc
includelib c:\masm32\lib\kernel32.lib
include c:\masm32\msvcrt\msvcrt.inc
includelib c:\masm32\msvcrt\msvcrt.lib
main PROTO
_difftime64 PROTO pTime1:PTR QWORD, pTime2:PTR QWORD, pDiff:PTR REAL8
WaitKeyCrt PROTO
; ---------------------
; literal string MACRO
; ---------------------
literal MACRO quoted_text:VARARG
LOCAL local_text
.data
local_text db quoted_text,0
align 4
.code
EXITM <local_text>
ENDM
; --------------------------------
; string address in INVOKE format
; --------------------------------
SADD MACRO quoted_text:VARARG
EXITM <ADDR literal(quoted_text)>
ENDM
__timeb64 STRUCT 8
time QWORD 0
millitm WORD 0
timezone SWORD 0
dstflag SWORD 0
__timeb64 ENDS
tm STRUCT 4
tm_sec SDWORD 0 ; seconds after the minute - [0,59]
tm_min SDWORD 0 ; minutes after the hour - [0,59]
tm_hour SDWORD 0 ; hours since midnight - [0,23]
tm_mday SDWORD 0 ; day of the month - [1,31]
tm_mon SDWORD 0 ; months since January - [0,11]
tm_year SDWORD 0 ; years since 1900
tm_wday SDWORD 0 ; days since Sunday - [0,6]
tm_yday SDWORD 0 ; days since January 1 - [0,365]
tm_isdst SDWORD 0 ; daylight savings time flag
tm ENDS
.data
align 8
time1 QWORD 0
time2 QWORD 0
diff REAL8 0.0
day REAL8 86400.0 ; 60*60*24
days REAL8 0.0
tstruct __timeb64 <0>
align 4
hmodule DWORD 0
pxmas DWORD 0
ptzname DWORD 0
tmpbuf BYTE 128 dup(0)
ampm BYTE "AM", 0
newline BYTE 13, 10, 0
.code
start:
invoke main
invoke WaitKeyCrt
invoke _exit, 0
main PROC uses edi
invoke _tzset
invoke printf, SADD("%s"), OFFSET newline
invoke printf, SADD("64-bit Time and Date Functions - C Run-time Library")
invoke printf, SADD("%s"), OFFSET newline
invoke _strtime, OFFSET tmpbuf
invoke printf, SADD(" OS time: %s"), OFFSET tmpbuf
invoke printf, SADD("%s"), OFFSET newline
invoke _strdate, OFFSET tmpbuf
invoke printf, SADD(" OS date: %s"), OFFSET tmpbuf
invoke printf, SADD("%s"), OFFSET newline
invoke _time64, OFFSET time1
invoke printf, SADD(" Time in seconds since UTC 1/1/1970: %I64d"), OFFSET time1
invoke printf, SADD("%s"), OFFSET newline
invoke _ctime64, OFFSET time1
invoke printf, SADD(" Time and date string: %s"), eax
invoke _gmtime64, OFFSET time1
invoke asctime, eax
invoke printf, SADD(" Coordinated universal time: %s"), eax
invoke _localtime64, OFFSET time1
mov edx, (tm PTR [eax]).tm_hour
.if edx >= 12
push eax
push edx
invoke strcpy, OFFSET ampm, SADD("PM")
pop edx
pop eax
sub edx, 12
mov (tm PTR [eax]).tm_hour, edx
.endif
mov edx, (tm PTR [eax]).tm_hour
.if edx == 0
mov (tm PTR [eax]).tm_hour, 12
.endif
invoke asctime, eax
add eax, 11
invoke printf, SADD( " 12-hour time: %.8s %s"), eax, OFFSET ampm
invoke printf, SADD("%s"), OFFSET newline
invoke _ftime64, OFFSET tstruct
movsx eax, tstruct.millitm
invoke printf, SADD(" Plus milliseconds: %u"), eax
invoke printf, SADD("%s"), OFFSET newline
xor edx, edx
movsx eax, tstruct.timezone
mov ecx, 60
div ecx
invoke printf, SADD(" Zone difference in hours from UTC: %u"), eax
invoke printf, SADD("%s"), OFFSET newline
invoke GetModuleHandle, SADD("MSVCRT")
mov hmodule, eax
invoke GetProcAddress, hmodule, SADD("_tzname")
.if tstruct.dstflag == 0
mov edx, [eax+0]
mov ptzname, edx
.else
mov edx, [eax+4]
mov ptzname, edx
.endif
invoke printf, SADD(" Time zone name: %s"), ptzname
invoke printf, SADD("%s"), OFFSET newline
invoke printf, SADD( " Daylight savings: ")
movsx eax, tstruct.dstflag
.if eax == 0
invoke printf, SADD("False")
.else
invoke printf, SADD("True")
.endif
invoke printf, SADD("%s"), OFFSET newline
invoke _localtime64, OFFSET time1
invoke strftime, OFFSET tmpbuf, SIZEOF tmpbuf, SADD("%A, %B %d, %Y"), eax
invoke printf, SADD(" Today is: %s"), OFFSET tmpbuf
invoke printf, SADD("%s"), OFFSET newline
invoke _localtime64, OFFSET time1
mov edx, 11 ; December
mov (tm PTR [eax]).tm_mon, edx
mov edx, 25 ; 25th
mov (tm PTR [eax]).tm_mday, edx
mov edx, 12 ; 12:00 noon
mov (tm PTR [eax]).tm_hour, edx
mov edx, 0
mov (tm PTR [eax]).tm_min, edx
mov edx, 0
mov (tm PTR [eax]).tm_sec, edx
mov edx, 0
mov (tm PTR [eax]).tm_wday, edx
mov edx, 0
mov (tm PTR [eax]).tm_yday, edx
mov edx, 0
mov (tm PTR [eax]).tm_isdst, edx
mov pxmas, eax
invoke _mktime64, eax
mov SDWORD PTR [time2+0], eax
mov SDWORD PTR [time2+4], edx
.if eax != -1 && edx != -1
invoke strftime, OFFSET tmpbuf, SIZEOF tmpbuf, SADD("%A, %B %d, %Y"), pxmas
invoke printf, SADD(" Christmas this year: %s"), OFFSET tmpbuf
invoke printf, SADD("%s"), OFFSET newline
.endif
invoke _difftime64, OFFSET time1, OFFSET time2, OFFSET diff
finit
fld diff
fld day
fdiv
fstp days
invoke printf, SADD(" Days until Christmas: %.0lf"), days
invoke printf, SADD("%s"), OFFSET newline
ret
main ENDP
_difftime64 PROC pTime1:PTR QWORD, pTime2:PTR QWORD, pDiff:PTR REAL8
; MS Visual C Run-time Library does not have a _difftime64 function so...
mov eax, pTime1
mov edx, pTime2
finit ; initialize FPU
; compare Time1 with Time2
fild QWORD PTR [edx] ; st(0) = Time2
fild QWORD PTR [eax] ; st(0) = Time1, st(1) = Time2
fcompp ; compare st(0) with st(1) and pop both registers
fstsw ax ; retrieve comparison result in the AX register
fwait ; insure the previous instruction is completed
sahf ; transfer the condition codes to the CPU's flag register
jb st0_less ; only the C0 bit (CF flag) would be set if no error
st0_greater: ; Time1 > Time2
;Subtract Time2 from Time1 to calculate the number of seconds difference
mov eax, pTime1
mov edx, pTime2
fild QWORD PTR [eax]
fild QWORD PTR [edx]
fsub
mov eax, pDiff
fstp REAL8 PTR [eax]
fwait
jmp @F
st0_less: ; Time2 > Time1
;Subtract Time1 from Time2 to calculate the number of seconds difference
mov eax, pTime2
mov edx, pTime1
fild QWORD PTR [eax]
fild QWORD PTR [edx]
fsub
mov eax, pDiff
fstp REAL8 PTR [eax]
fwait
@@:
ret
_difftime64 ENDP
WaitKeyCrt PROC
invoke printf, SADD("%s"), OFFSET newline
invoke printf, SADD("Press any key to continue...")
invoke _getch
ret
WaitKeyCrt ENDP
END start