Hi everyone.

Okay, here is my dilemma. I have an old app laying around which was written in Delphi. This app displays OS version information in this format:

Operating System: Windows XP 5.1 build 2600 (Service Pack 1)

It does this for ALL versions of windows from 95 and up. In delphi this was easy, but I am at a loss as to how to achieve this in MASM. If someone can just nudge me in the right direction, it would be a big help. :)

Many thanks in advance!
Posted on 2003-06-16 17:09:34 by The Beginner
Look at API function GetVersionEx .

RobotBob
Posted on 2003-06-16 21:14:07 by RobotBob
Do you mean when you right click the .exe and select properties? That's set by the resource script, Like this:



1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040C04E4" //Block: language ID = French, char set = Windows, Multilingual
BEGIN
VALUE "CompanyName", "http://www.asmcommunity.net/board/index.php\0"
VALUE "FileDescription", "Adding Scripting capabilities to an exe\0"
VALUE "FileVersion", "01,23,04,2003\0"
VALUE "InternalName", "ScripTxt\0"
VALUE "OriginalFilename", "ScripTxt.exe\0"
VALUE "ProductName", "ScripTxt\0"
VALUE "ProductVersion", "03.04.2003\0"
VALUE "Comments", "Revised by near everyone\0"
VALUE "LegalCopyright", "Freeware for non commercial use\0"
VALUE "OLESelfRegister","\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x040C, 1252
END
END


(This isn't a COM dll, its an exeacutable. ToutEnMasm added it to one of my projects when he was fixing it.)
Posted on 2003-06-19 23:17:37 by Ernie
If you're using RadASM you can set the versioninfo by selecting Versioninfo from the project menu and filling in the values. It will auto-generate the RC script for you, you should do it from the menu in RadASM as it makes updating easier and using version-inc you can have it auto-increment build numbers.
Posted on 2003-06-20 00:47:04 by donkey
Thanks everyone, but I was asking about OS version information as I asked in my post above. :)
Posted on 2003-06-22 08:44:27 by The Beginner
That was the GetVersionEx answer, all the information you need about the OS is from that api. You have to build the strings yourself.
Posted on 2003-06-22 09:50:29 by donkey
Using wsprintf most likely I suppose.
Posted on 2003-06-22 10:04:27 by roticv
Alot of the return values are just numbers.
You'll have to look at msdn to find the associated strings.
(like donkey states)
But this gives you more power. Instead of Win98 Second Edition, you could call it "M$ Bloated Dos Shell 98SE!" /jk :grin:

It is really easy to use. I use it for tests to see what platform my app is running on. In this instance (testing platform versions for features) the associated string are not needed.

RobotBob
Posted on 2003-06-22 17:38:22 by RobotBob

That was the GetVersionEx answer, all the information you need about the OS is from that api. You have to build the strings yourself.


I guess the problem is building the strings. In Delphi, it was easy:



function GetWindowsVersion: String;
var
lpOS: TOsVersionInfo;
build: String;
begin
lpOS.dwOSVersionInfoSize := SizeOf(OsVersionInfo);
GetVersionEx(lpOS);

case lpOs.dwPlatformId of
VER_PLATFORM_WIN32_NT:
begin
build := ' build ' + IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')'; //Windows build and SP
if build = '' then build := '(No Service Pack Installed)';
if (lpOS.dwMajorVersion <= 4) then
result := 'Windows NT ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build; //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')';;
if ((lpOS.dwMajorVersion = 5) and (lpOS.dwMinorVersion = 0)) then
result := 'Windows 2000 ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')'
else
if ((lpOS.dwMajorVersion = 5) and (lpOS.dwMinorVersion = 1)) then
result := 'Windows XP ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build; //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')'
end;
VER_PLATFORM_WIN32_WINDOWS:
begin
if ((lpOS.dwMajorVersion > 4) or ((lpOS.dwMajorVersion = 4) and (lpOS.dwMinorVersion = 0))) then
result := 'Windows 98 ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')'
else
if ((lpOS.dwMajorVersion > 4) or ((lpOS.dwMajorVersion = 4) and (lpOS.dwMinorVersion = 90))) then
result := 'Windows ME ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')'
else
result := 'Windows 95 ' + IntToStr(lpOS.dwMajorVersion) + '.' + IntToStr(lpOS.dwMinorVersion) +
build; //IntToStr(lpOS.dwBuildNumber) + ' (' + lpOS.szCSDVersion + ')';
end
else
result := 'Win32s';
end;
end;


Now, for me at least, building a proc or function like the one above is a bit difficult. I guess you can't just simply "add" strings in MASM and I am told that I need to use lstrcat, but how do you do it like I do in the code above? Yes... still learning. Forgive me. :)

Anyhow, thanks everyone. I appreciate your generous attempts at helping me with this.
Posted on 2003-06-22 18:22:40 by The Beginner
I made this quickly so don't expect much from this.
It functions just like the code you posted. And I tried to make it
look comfortable to someone coming from a hll.
I know the standard boards rules are not to generate full code for someone.
When its not 'homework' related, I wouldn't want you to get frustrated and go back
to delphi :)

Here is the code in masm32 format, SpAsm format on request :)



; #################################################
; Using hll macros and apis for formatting.
; Also there are too many wsprintfs, this should
; called at the end. It took me 15 minutes and
; It could be made more efficent. Like -not- using
; wsprintf :) Purists beware.
; I guess it makes it more understandable since
; the original delphi post looks close to this.
; This looks god-awfully close to C doesn't it.

; So 'The Beginner' wsprintf is handy. Everyone
; on this board seems to like it. However ASM
; is powerful in string manipulations. Don't
; always lean toward an api. You will remove
; the power that asm gives you if you do so.
; But its close to your previous ways of parsing,
; it will help in learning and minimize any hair
; pulling.
.486
.model flat, stdcall
option casemap :none ; case sensitive
; #################################################

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

main PROTO
; #################################################
.data?
osver OSVERSIONINFO <>
; Blindly make large buffers, not a good idea
; I am in a hurry however :0
OutPutBuffer db 50 dup(?)
ServPack db 25 dup(?)
; #################################################
.data
AppTitle db "GetVersionEx Example",0
NoServicePack db "No Service Pack Installed",0
WinNT db "Windows NT %i.%i build %i (%s)",0
Win98 db "Windows 98 %i.%i build %i (%s)",0
Win95 db "Windows 95 %i.%i build %i (%s)",0
Win2000 db "Windows 2000 %i.%i build %i (%s)",0
WinXP db "Windows XP %i.%i build %i (%s)",0
WinME db "Windows ME %i.%i build %i (%s)",0
; #################################################
.code
start:
call main
invoke ExitProcess,0
; #################################################

main proc
; Must fill this dword with the OSVERSIONINFO struct size
mov DWORD PTR [osver.dwOSVersionInfoSize], 148
invoke GetVersionEx,OFFSET osver

.IF osver.dwPlatformId == VER_PLATFORM_WIN32_NT
.IF osver.szCSDVersion == NULL
invoke lstrcat,OFFSET ServPack,OFFSET NoServicePack
.ELSE
invoke lstrcat,OFFSET ServPack,OFFSET osver.szCSDVersion
.ENDIF


.IF osver.dwMajorVersion <= 4
invoke wsprintf,OFFSET OutPutBuffer,OFFSET WinNT,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0
invoke wsprintf,OFFSET OutPutBuffer,OFFSET Win2000,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1
invoke wsprintf,OFFSET OutPutBuffer,OFFSET WinXP,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack
.ENDIF

.ELSEIF osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS

.IF osver.dwMajorVersion > 4 || osver.dwMajorVersion == 4 && osver.dwMinorVersion == 0
invoke wsprintf,OFFSET OutPutBuffer,OFFSET Win98,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack

.ELSEIF osver.dwMajorVersion >= 4 && osver.dwMinorVersion == 90
invoke wsprintf,OFFSET OutPutBuffer,OFFSET WinME,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack
.ELSE
invoke wsprintf,OFFSET OutPutBuffer,OFFSET Win95,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack
.ENDIF

.ENDIF
; And Display Our Result..Woohoo
invoke MessageBox,0,OFFSET OutPutBuffer,OFFSET AppTitle,MB_OK
ret

main endp
; #################################################
end start


The boards software may wrap some of these lines, it should be obvious where it happens.

It works on my machine, granted it means only one test works for sure :)
it display for me Windows XP 5.1 build 2600 Service Pack 1

Good Luck,
RobotBob
Posted on 2003-06-22 21:46:49 by RobotBob
Nice job RobotBob,

I'm not averse to wsprintf myself so do you mind if I steal your code for a sniplet (duly creditted ofcourse) ?
Posted on 2003-06-22 21:56:14 by donkey
Credit me if you like or not , although credit warms my ego :grin:
It most likely has bug, and the guessed buffers sizes are a bad idea.

Hopefully it displays right on everyones platform, I dont expect it not to..who knows.

BTW I started using RADAsm. Mainly to play with GoAsm and those times I
must use the evil empires assembler. :)

EDIT: oh and feel free to edit or remove the whining comment at the top :)

RobotBob
Posted on 2003-06-22 22:05:49 by RobotBob
This works and minimizes the number of wsprintfs in the exe.
Without using a subroutine or proc (overhead of jmp-stack-ret).

There still is the buffer thing, but maybe later:)
oh and error checking...



; Add this to your .data? section
; call it whatever you like.
.data?
OsStringPtr dd ?

;Ok a cleaner main proc
main proc
; Must fill this dword with the OSVERSIONINFO struct size
mov DWORD PTR [osver.dwOSVersionInfoSize], 148
invoke GetVersionEx,OFFSET osver

.IF osver.dwPlatformId == VER_PLATFORM_WIN32_NT
.IF osver.szCSDVersion == NULL
invoke lstrcat,OFFSET ServPack,OFFSET NoServicePack
.ELSE
invoke lstrcat,OFFSET ServPack,OFFSET osver.szCSDVersion
.ENDIF

.IF osver.dwMajorVersion <= 4
mov eax, OFFSET WinNT
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0
mov eax, OFFSET Win2000
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1
mov eax, OFFSET WinXP
mov OsStringPtr, eax

.ENDIF

.ELSEIF osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS

.IF osver.dwMajorVersion > 4 || osver.dwMajorVersion == 4 && osver.dwMinorVersion == 0
mov eax, OFFSET Win98
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion >= 4 && osver.dwMinorVersion == 90
mov eax, OFFSET WinME
mov OsStringPtr, eax

.ELSE
mov eax, OFFSET Win95
mov OsStringPtr, eax

.ENDIF
.ENDIF

; Format And Display Our Result..Woohoo
invoke wsprintf,OFFSET OutPutBuffer,OsStringPtr,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack
invoke MessageBox,0,OFFSET OutPutBuffer,OFFSET AppTitle,MB_OK
ret

main endp


I hope this works well, it seems to.
And its smaller.

You could do a push push pop pop to exhange.
But it becomes less understandable.

RobotBob
Posted on 2003-06-23 13:30:13 by RobotBob
Wow!

I only wanted hints, but you did something you didn't have to by going the extra mile and showing me some nice code! Thank you very much, RobotBob! This is very much appreciated!

I am going to kick this around now and see how it works out. I will let ya know what I do to it. :)

Thanks again everyone!
Posted on 2003-06-24 12:29:10 by The Beginner
Nothing major, I just need to look att he msdn site to compare os version numbers.
Its reporting win98 first edition as win95. Its because win95 is determined by an else clause.

I am glad its helpful. I know not being able to just "Connect" + "String" + " Literals" can be quite a change.

EDIT: If you want to fix it, then go ahead, I did jump past hints straight into app :) I was afraid you would consider this to be difficult compared to delphi. Not so.

Edit2:here is the msdn link fixing the bug is easy ,just look at the versions.
RobotBob
Posted on 2003-06-24 13:59:36 by RobotBob
I had some time to kill so here is a fixed version:
-full source-



; #################################################
; Using hll macros and apis for formatting.
; I guess it makes it more understandable since
; the original delphi post looks close to this.
; This looks god-awfully close to C doesn't it.

.486
.model flat, stdcall
option casemap :none ; case sensitive
; #################################################

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

main PROTO
; #################################################
.data?
osver OSVERSIONINFO <>
; Blindly make large buffers, not a good idea
; I am in a hurry however :0
OutPutBuffer db 50 dup(?)
ServPack db 128 dup(?)
OsStringPtr dd ?
; #################################################
.data
AppTitle db "GetVersionEx Example",0
NoServicePack db "No Service Pack Installed",0
WinNT db "Windows NT %i.%i build %i (%s)",0
Win98 db "Windows 98 %i.%i build %i (%s)",0
Win95 db "Windows 95 %i.%i build %i (%s)",0
Win2000 db "Windows 2000 %i.%i build %i (%s)",0
WinXP db "Windows XP %i.%i build %i (%s)",0
WinME db "Windows ME %i.%i build %i (%s)",0
SE db "Second Edition",0
; #################################################
.code
start:
call main
invoke ExitProcess,0
; #################################################

main proc
; Must fill this dword with the OSVERSIONINFO struct size
mov DWORD PTR [osver.dwOSVersionInfoSize], 148
invoke GetVersionEx,OFFSET osver

.IF osver.dwPlatformId == VER_PLATFORM_WIN32_NT
.IF osver.szCSDVersion == NULL
invoke lstrcat,OFFSET ServPack,OFFSET NoServicePack
.ELSE
invoke lstrcat,OFFSET ServPack,OFFSET osver.szCSDVersion
.ENDIF

.IF osver.dwMajorVersion <= 4
mov eax, OFFSET WinNT
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0
mov eax, OFFSET Win2000
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion == 5 && osver.dwMinorVersion == 1
mov eax, OFFSET WinXP
mov OsStringPtr, eax
.ENDIF

.ELSEIF osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS

.IF osver.dwMajorVersion > 4 || osver.dwMajorVersion == 4 && osver.dwMinorVersion == 0
mov eax, OFFSET Win95
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion >= 4 && osver.dwMinorVersion == 90
mov eax, OFFSET WinME
mov OsStringPtr, eax

.ELSEIF osver.dwMajorVersion >= 4 && osver.dwMinorVersion == 10
.IF osver.szCSDVersion == 'A'
; Don't worry about clearing ServPack, in this case it only contained
; one byte anyway.
invoke lstrcat,OFFSET ServPack,OFFSET SE
.ENDIF
mov eax, OFFSET Win98
mov OsStringPtr, eax
.ENDIF

.ENDIF

; Format And Display Our Result..Woohoo
invoke wsprintf,OFFSET OutPutBuffer,OsStringPtr,osver.dwMajorVersion, \
osver.dwMinorVersion,osver.dwBuildNumber,OFFSET ServPack
invoke MessageBox,0,OFFSET OutPutBuffer,OFFSET AppTitle,MB_OK
ret

main endp
; #################################################
end start


Beware of the wrapping,

RobotBob
Posted on 2003-06-28 02:12:42 by RobotBob