;  getcoll.asm
;
;  This Microsoft Windows 3.1 routine gets the DOS Collate Sequence
;  Table and returns the real mode pointer to the calling function.
;  This routine circumvents a problem in the Windows 3.1 Standard mode
;  kernel by issuing a DPMI Simulate Real Mode Interrupt call.
;
;  C prototype:
;   char FAR *getcoll(unsigned codepage, unsigned country);
;
;  Assembly instructions:
;   TASM /m2 /mx getcoll
;   (that is, use two pass assembly and case sensitive exports)
;
;  written on Tue  04-12-1994  by Ed Beroset
;  and released to the public domain by the author
;
        IDEAL
        MODEL small, C
        P286N             ; allow all 286 non protected mode instructions
        global getcoll:PROC
        global pascal GLOBALDOSALLOC:FAR
        global pascal GLOBALDOSFREE:FAR

        CODESEG
PROC getcoll codepage:WORD, country:WORD
        LOCAL   MemBlock:WORD, RealRegs:WORD:19h
        USES    bx, cx, di, es
        mov     cx,19h                  ; clear the RealRegs structure
        xor     ax,ax                   ; zeroes will do nicely
        mov     di,ss                   ; it's on the stack
        mov     es,di                   ;
        lea     di,[RealRegs]           ; es:di==>RealRegs
        cld                             ; go forward
        rep     stosw                   ; whip it good
        mov     cx,5                    ; allocate data bytes required
        call    GLOBALDOSALLOC pascal,0,cx; from DOS memory
        mov     [RealRegs+22h],dx       ; save real mode segment
        mov     [MemBlock],ax           ; save prot mode descriptor
        or      dx,ax                   ; if there was an error, exit
        jz      @@exit                  ;
        mov     ax,[codepage]           ; recall code page
        mov     [RealRegs+10h],ax       ; put in BX entry of RealRegs
        mov     ax,[country]            ; recall country code
        mov     [RealRegs+14h],ax       ; put in DX entry of RealRegs
        mov     [RealRegs+18h],5        ; store buff size in CX
        mov     [RealRegs+1Ch],6506h    ; the function number for DOS in AX
        pushf                           ;
        pop     ax                      ; a direct pop could be used,
        mov     [RealRegs+20h],ax       ;   but this is more straightforward
        mov     bx,21h                  ; perform Int 21h (DOS)
        xor     cx,cx                   ; pass nothing on stack
        mov     ax,300h                 ; DPMI Simulate Real Mode Int
        mov     di,ss                   ; point to our datablock again
        mov     es,di                   ;
        lea     di,[RealRegs]           ; reload pointer offset
        int     31h                     ; do it
        mov     es,[MemBlock]           ; point to our Memory Block
        jc      @@bogus                 ; if error, leave
        xor     di,di                   ; point to our block again
        cmp     [BYTE es:di],6          ; check to see if it's valid
        jnz     @@bogus                 ; if it isn't, leave
        mov     dx,[WORD es:di+3]       ; pointer struc is [6, offs, seg]
        mov     ax,[WORD es:di+1]       ; return dx:ax==>table (real mode)
        jmp     @@freemem               ;
@@bogus:                                ;
        xor     dx,dx                   ; otherwise hand back a NULL ptr
        xor     ax,ax                   ;
@@freemem:                              ;
        push    ax                      ;
        push    dx                      ;
        call    GLOBALDOSFREE pascal,es ; free our precious memory
        pop     dx                      ;
        pop     ax                      ;
@@exit:
        RET                             ; a macro -- actually pops regs, too
ENDP getcoll

        END

