The MASM Forum Archive 2004 to 2012

Project Support Forums => MASM32 => Topic started by: hutch-- on January 20, 2005, 09:44:49 AM

Title: msvcrt include and library.
Post by: hutch-- on January 20, 2005, 09:44:49 AM
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]
Title: Re: msvcrt include and library.
Post by: Vortex on January 20, 2005, 12:22:35 PM
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]
Title: Re: msvcrt include and library.
Post by: hutch-- on January 20, 2005, 03:01:14 PM
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.
Title: Re: msvcrt include and library.
Post by: hutch-- on January 21, 2005, 07:57:07 AM
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.
Title: Re: msvcrt include and library.
Post by: Vortex on January 21, 2005, 08:59:10 AM
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
Title: Re: msvcrt include and library.
Post by: MazeGen on January 21, 2005, 11:10:36 AM
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++.
Title: Re: msvcrt include and library.
Post by: Vortex on January 21, 2005, 11:38:05 AM
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.
Title: Re: msvcrt include and library.
Post by: 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?
Title: Re: msvcrt include and library.
Post by: MichaelW on January 21, 2005, 01:58:56 PM
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).


Title: Re: msvcrt include and library.
Post by: Vortex on January 21, 2005, 06:30:07 PM
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.
Title: Re: msvcrt include and library.
Post by: P1 on January 21, 2005, 06:55:01 PM
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)

Title: Re: msvcrt include and library.
Post by: MazeGen on January 21, 2005, 08:05:17 PM
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...
Title: Re: msvcrt include and library.
Post by: MichaelW on January 22, 2005, 12:10:15 PM
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
Title: Re: msvcrt include and library.
Post by: MichaelW on January 24, 2005, 12:01:00 PM
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'

Title: Re: msvcrt include and library.
Post by: pbrennick on January 24, 2005, 03:48:15 PM
MichaelW,
Very nice work.
Paul
Title: Re: msvcrt include and library.
Post by: GregL on January 31, 2005, 09:07:27 PM
Vortex,

Didn't you already do this once? What is the difference between your include and library and this one of Hutch's?
Title: Re: msvcrt include and library.
Post by: Vortex on February 01, 2005, 10:55:42 AM
Hi Greg,

My tool creates the include file form msvcrt.dll, plus Pelle's library manager creates an import library for this DLL
Title: Re: msvcrt include and library.
Post by: Vortex on February 12, 2005, 01:10:10 PM
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
Title: Re: msvcrt include and library.
Post by: MazeGen on February 12, 2005, 03:13:04 PM
 :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
Title: Re: msvcrt include and library
Post by: Mark Jones on March 05, 2005, 04:03:04 PM
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]
Title: Re: msvcrt include and library.
Post by: James Ladd on March 05, 2005, 09:54:59 PM
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 ?
Title: Re: msvcrt include and library.
Post by: Vortex on March 06, 2005, 01:06:16 PM
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]
Title: Re: msvcrt include and library.
Post by: Xor Stance on March 06, 2005, 05:17:18 PM
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.
Title: Re: msvcrt include and library.
Post by: Mark Jones on March 06, 2005, 09:35:41 PM
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.
Title: Re: msvcrt include and library.
Post by: MichaelW on March 06, 2005, 10:16:19 PM
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.
Title: Re: msvcrt include and library.
Post by: GregL on March 06, 2005, 11:58:46 PM
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