> Hi, this does not work out, as _imp_CreateWindowExW@48 does not exist
> (I am using MASM32)

Well, you must declare it as external of course, for example:

externdef stdcall _imp_CreateWindowExW@48:dword
Posted on 2004-10-27 02:55:58 by japheth
I'm actually working on a switched ANSI/Unicode application at the moment (it needs to be able to use and display non-Roman characters under XP, but use Roman characters only under 9x and ME).

So I put together some parts of the code to demonstrate the sort of thing required:-

;By Jeremy Gordon 27th October 2004

;
;This code demonstrates how to used switched calls to the APIs to write
;an application which will work under Windows 9x/ME and also under NT/2000/XP.
;There are two reasons for using switched calls here. Firstly, an application
;which calls an API which does not exist in the system will not load. So
;here you are making sure that when running under Windows 9x/ME the calls to
;the Unicode APIs are not called directly. Secondly this is an easy way to
;call the correct API at run-time.
;
;Using switching in this way is only necessary if you want to use non-Roman
;characters in the application.
;
;If you are using Roman characters throughout, for example English, you can
;either use the ANSI APIs throughout (they work equally well on NT/2000/XP)
;or you can use the Microsoft Layer for Unicode (MSLU). This can easily
;be achieved using GoLink, which has its own MSLU loader. See my article
;"Writing Unicode Programs" one of the tutorials on the GoAsm web site.
;
;A third alternative is to use different versions of your program, one
;for 9x/ME and one for NT/2000/XP.
;
;This code is in GoAsm format. See http://www.GoDevTool.com
;
DATA
;
;Here we concentrate on the APIs in User32.dll only. This must be done
;for each of the DLLs we will be using.
;
USERNAME_ASSTRINGS DB 'GetClassLongA',0 ;USERSCALLS+0h
DB 'GetWindowLongA',0 ;USERSCALLS+4h
DB 'SendMessageA',0 ;USERSCALLS+8h
DB 'RegisterClassA',0 ;USERSCALLS+Ch
DB 'SendDlgItemMessageA',0 ;USERSCALLS+10h
DB 'CallWindowProcA',0 ;USERSCALLS+14h
DB 'CreateWindowExA',0 ;USERSCALLS+18h
DB 'UnregisterClassA',0 ;USERSCALLS+1Ch
DB 'SetWindowTextA',0 ;USERSCALLS+20h
DB 'DefWindowProcA',0 ;USERSCALLS+24h
DB 'CreateDialogParamA',0 ;USERSCALLS+28h
DB 'GetClassInfoA',0 ;USERSCALLS+2Ch
DB 'DialogBoxParamA',0 ;USERSCALLS+30h
DB 'MessageBoxA',0 ;USERSCALLS+34h
DB 'LoadMenuA',0 ;USERSCALLS+38h
DB 'InsertMenuItemA',0 ;USERSCALLS+3Ch
DB 'DrawTextExA',0 ;USERSCALLS+40h
DB ' ',0 ;spare entry
DB 0FFh ;end stop
USERNAME_WSSTRINGS DB 'GetClassLongW',0 ;USERSCALLS+0h
DB 'GetWindowLongW',0 ;USERSCALLS+4h
DB 'SendMessageW',0 ;USERSCALLS+8h
DB 'RegisterClassW',0 ;USERSCALLS+Ch
DB 'SendDlgItemMessageW',0 ;USERSCALLS+10h
DB 'CallWindowProcW',0 ;USERSCALLS+14h
DB 'CreateWindowExW',0 ;USERSCALLS+18h
DB 'UnregisterClassW',0 ;USERSCALLS+1Ch
DB 'SetWindowTextW',0 ;USERSCALLS+20h
DB 'DefWindowProcW',0 ;USERSCALLS+24h
DB 'CreateDialogParamW',0 ;USERSCALLS+28h
DB 'GetClassInfoW',0 ;USERSCALLS+2Ch
DB 'DialogBoxParamW',0 ;USERSCALLS+30h
DB 'MessageBoxW',0 ;USERSCALLS+34h
DB 'LoadMenuW',0 ;USERSCALLS+38h
DB 'InsertMenuItemW',0 ;USERSCALLS+3Ch
DB 'DrawTextExW',0 ;USERSCALLS+40h
DB ' ',0 ;spare entry
DB 0FFh ;end stop
ALIGN 4
;
USERSCALLS DD 18 DUP 0 ;to hold calls to APIs in User32.dll
PLATFORM_ID DD 0 ;to hold the system we are running on
BUFFER DB DUP 1000h ;general 4K buffer
;
CODE
;
START:
;
;***************** first find out what system we are running on
MOV ESI,ADDR BUFFER
MOV D[ESI],148 ;OSVERSIONINFO structure size
PUSH ESI
CALL GetVersionExA ;this API works on both platforms
MOV EAX,[ESI+10h] ;get platform id
MOV [PLATFORM_ID],EAX ;keep that
;
;***************** next get the APIs from User32.dll
PUSH 'User32.dll'
CALL LoadLibraryA ;get handle of User32.dll
OR EAX,EAX ;check for eax=0
JZ >L50 ;error exit
MOV EBX,EAX ;keep handle in ebx
MOV EDI,ADDR USERSCALLS ;get place to put API addresses
MOV ESI,ADDR USERNAME_ASSTRINGS ;get list of API names (ANSI)
CMP D[PLATFORM_ID],1 ;see if NT,2000,XP and above
JNA >L18 ;no, use ANSI APIs
MOV ESI,ADDR USERNAME_WSSTRINGS ;get list of API names (Unicode)
L18:
CALL GET_CALLS ;see this procedure further down this source
JC >L50 ;error exit (to somewhere not shown here)
;
;****************** now make a message box
;****************** note that if you are writing to the message box in
;****************** "Roman" characters you might as well just use
;****************** CALL MessageBoxA which works both under 9x and NT\XP.
;****************** However if you want to write to the message box
;****************** in non-Roman characters eg. Chinese. Cyrillic etc
;****************** then you would use this switched version
;
;****************** The following supposes that the string for the
;****************** message box is already in BUFFER
;
PUSH 40h ;information + ok button
CMP D[PLATFORM_ID],1 ;see if NT,2000,XP and above
JNA >L244 ;no
PUSH L'Hello in Unicode';push pointer to Unicode string using L override
JMP >L246
L244:
PUSH 'Hello in ANSI' ;push pointer to ANSI string
L246:
PUSH ADDR BUFFER,0 ;push message, followed by message box owner
CALL [USERSCALLS+34h] ;CALL either MessageBoxA or MessageBoxW
;
;
; rest of the code goes here
;
;**********************************************************************
;
GET_CALLS:
L1:
CMP B[ESI],20h ;see if spare entry
JZ >L2 ;yes, jump over this one
PUSH ESI,EBX
CALL GetProcAddress
OR EAX,EAX ;see if successful
JZ >L4 ;no, drop out
L2:
STOSD ;insert API address into call destination
L3:
LODSB ;get to end of this API name
OR AL,AL ;see if end of last string yet
JNZ L3 ;no
CMP B[ESI],0FFh ;see if finished function list
JNZ L1 ;no, so use this string
RET
L4:
STC ;return c if failed, nc if succeeded
RET
Posted on 2004-10-27 03:30:15 by jorgon