file version comparison

Everything else that doesn't fall into one of the other PB categories.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

file version comparison

Post by SFSxOI »

I know I saw this somewhere in the forums (i think) but can't find it now, I think it was actually part of something else, a way to compare the versions of two files to determine which one is the greater/newer version. Anyone have this or a way to do it?
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

How would you define newer? GetFileDate() with the modified flag?
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

I define newer in this case ; as a greater file version then the previous file of the same name.

I had considered the date but thats no good to me as its possible to have two of the same file with the same date but with different versions. Since the files i'm after do have versions and each sucessive file has a different (greater) version number (but its possible they could have the same date), I need to compare the file versions and not the date.

I also can't count on the file hash because i will not know what the file hash of a newer file will be in the future.

I think i can do it with a bunch of If's : EndIf's after breaking down the file number and comparing each part of it to a previous version. Maybe its as simple as doing something stupid like this (pseudo code stuff kinda):

Code: Select all

; because the version number has the format below, and any part of the version number can change for a sucessive version....

(format of version number  = <major-version>.<minor-version>.<build>.<update>)
known_compare_base_file_version = 5.4.3790.1000

majver = (get the string 5)
minver = (get the string 4)
bldver = (get the string 3790)
updver = (get the string 1000)

if majver => 5
maj = 1
endif

if minver => 4 and maj = 1
min = 1
endif

if bldver => 3790 and maj = 1 and min = 1
bld = 1
endif

if updver =>1000 and maj = 1 and min = 1 and bld = 1
upd = 1
endif

if maj + min + bld + upd = 4

version is ok

else

version is not OK
endif

or...some such nonsense :)
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

off the top of my head :)

If all the numbers between the dots are going to be less that 32k then get a union structure of 4 words in a quad, fill the words with val() and take the highest quad
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Not sure what type of files you mean, but if it's exe or dll files on Windows this might be of use: http://www.purebasic.fr/english/viewtopic.php?t=13910

Also, you need to decide how to treat the version info.

x1.x2.x3.x4

Now, normally x4 is usually a build (some may put the build in x3 instead though), it's for information purposes and usually internal, if the version is unchanged the only ones seeing a change in build would be the developer(s) of the software as a new release would change the version as well.

x3 is usually the update or patch, so if it's 0 then it's the first release a 1 could indicate a bugfix, patch, or Release Candidate etc.

x2 is the revision or minor version, usually this indicate there are changes or additions but that it is still compatible within the same major version.

x1 if this changes then it usually means is not compatible with other major versions.

These are not absolute rules, but they are good guidelines as most do it this way or close to it so it helps reduce confusion (which is bad enough)

Also note that leading 0's are ignored, in other words each "x" number are seperate and not fractions. So 1.001.0.14 is the same as 1.1.0.14
A higher number is thus a more recent one, this allows easy and fast integer comparisons.

Again this is a guideline, in the world of string based version info there is a lot of weird stuff like letters or even floating point like fractions O.o

I prefer to stay clos to how windows does it which is also how PureBasic ads version info to the dll and exe manifests.

If you want to cry....read this: http://en.wikipedia.org/wiki/Software_versioning :lol:

Not the most elegant solution but it's simple, works, and give you a place to start and modify from :)

Code: Select all

EnableExplicit 

Procedure.i CompareVersion(ver.l,rev.l,subver.l,subrev.l,oldver.l,oldrev.l,oldsubver.l,oldsubrev.l,flag.l=4)
 Protected result.i=0
 If flag>0
  If ver<oldver
   result=-1
  ElseIf ver>oldver
   result=1
  Else
   If flag>1
    If rev<oldrev
     result=-1
    ElseIf rev>oldrev
     result=1
    Else
     If flag>2
      If subver<oldsubver
       result=-1
      ElseIf subver>oldsubver
       result=1
      Else
       If flag>3
        If subrev<oldsubrev
         result=-1
        ElseIf subrev>oldsubrev
         result=1
        Else
         result=0
        EndIf
       EndIf
      EndIf
     EndIf
    EndIf
   EndIf
  EndIf
 EndIf
 ProcedureReturn result
EndProcedure

Debug CompareVersion(1,2,3,4,1,2,3,4) ;0 if they are the same
Debug CompareVersion(2,2,3,4,1,2,3,4) ;1 if the first 4 params are higher than the last 4
Debug CompareVersion(0,2,3,4,1,2,3,4) ;-1 if the first 4 params are lower than the last 4

;Use the flag param to indicate how many params should be compared.
Debug CompareVersion(1,2,4,0,1,2,3,4,2) ;compare only the two first of the params
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

pdwyer wrote:off the top of my head :)

If all the numbers between the dots are going to be less that 32k then get a union structure of 4 words in a quad, fill the words with val() and take the highest quad
Unfortunately at least on Windows VS_FIXEDFILEINFO indicate they are stored as two 32bit (MSb and then LSb) and I seem to recall elsewhere that the Windows file version numbers range 0-65535, so a structure union of words and using a quad to compare would work... if we had unsigned quads :P It's still possible though, but would need a little kludge of code to handle the signed issue/wrap in this case. Although to be honest, I doubt that anyone will have a full version number larger than: 32767.x.x.x though, at least I can't recall seeing one, I'd still advise adding a sign check in any case.

PS! I remembered that some people tend to use dates in some form for the version info in that case there might be very large numbers unfortunately.
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Gah I'm spam posting tonight...

In case anyone are wondering this is how I've "standardized" my versioning on my exe's and dll's.

x1.x2.x3.x4

x1 = version (aka major version)
x2 = revision (aka minor version)
x3 = release (aka update/patch/bugfix, major revision, sub version)
x4 = build (aka minor revision, sub revision)

If x1 changed this usually means the "next gen" of my software, large changes or stuff even removed, not normally "compatible" with older versions.

If x2 changed this usually means the next evolution of my software, stuff has been added or improved, functionality the same or better, should be compatible with previous releases of the same major version.

If x3 changed this usually means the release, at each release this increases from 0 (first release of this version.revision) and up, indicating small changes, a bug fix, or even just a documentation change. (It might jump a few numbers between actual releases though)

x4 always change, at each change of x3 this is reset to 0 again though, this helps "catch myself" when I do some tweaking, so I know that I changed the release after it actually was released, thus the build is for internal use only, and I sometimes use it as a alpha count when working on the next version.revision too. It is rare that x4 is 0 though as I tend to do a few "builds" before packaging it for release. (So if build is 53 this means it took 53 more builds before I felt that i.e v2.1.0 was ready for release)

To put it another way, the numbers to the left has a higher priority than the ones on the right of a . which is quite logical I hope.

That's how I do it, anyway I'll shut up now, I think I've "hijacked" this thread enough. :oops:
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

There are some places in the Windows OS where the only way to judge if a newer file has been put in place is by comparing the file version against a fixed known value because it affects what methods you use sometimes. For example > http://msdn.microsoft.com/en-us/library ... S.85).aspx where the only way to decide if WUA or SUS is to be used. The version installed will dictate if your code works or not in that particular area. The format of the version number is format of version number = <major-version>.<minor-version>.<build>.<update>. The <update> on the end doesn't matter as long as the rest of the numbers are greater or lesser.

If for example (from the link above) the file version I need to design for has to be greater then 5.4.3790.1000 and the file version thats actually installed on the computer is 5.4.2790.1000 then it means that SUS will be used instead of WUA. So this would be kind of important for correct across network updates at times because it would affect how the updates are pushed down and if I needed to reserve server space or machine cache space for the updates or if i needed to store every update first then push it down or just prompt the download and install from Windows Update its self, etc...... Lots of things.

So, if I know the dividing line verson number ( if => 5.4.3790.1000 then WUA is used, else SUS is used) i'll know which way to go. So I need to check the file on the computer first to decide which to use.

This is what i came up with so far, a simple If:Else:EndIf type filter thing that works, but i'm looking at ya'lls examples too:

Code: Select all

Procedure.s Compare_File_Versions_for_WinUpdate(In_Compare_Version$)
Known_majver.i = 5
Known_minver.i = 4 
Known_bldver.i = 3790

file_majver.i = Val(StringField(In_Compare_Version$, 1, "."))
file_minver.i = Val(StringField(In_Compare_Version$, 2, ".")) 
file_bldver.i = Val(StringField(In_Compare_Version$, 3, "."))

If file_majver => Known_majver
ok_majver.i = 1
Else
ok_majver.i = 0
EndIf

If (file_minver => Known_minver) Or (ok_majver = 1)
ok_minver.i = 1
Else
ok_minver.i = 0
EndIf

If (file_bldver => Known_bldver) Or (ok_majver = 1) Or (ok_minver = 1)
ok_bldver.i = 1
Else
ok_bldver.i = 0
EndIf

If (file_bldver < Known_bldver) And (ok_majver = 1) And (ok_minver = 1)
ok_bldver.i = 1
Else
ok_bldver.i = 0
EndIf

If ok_majver + ok_minver + ok_bldver = 3  
yes_no$ = "good"
Else
yes_no$ = "bad"
EndIf

ProcedureReturn yes_no$

EndProcedure
User avatar
Demivec
Addict
Addict
Posts: 4283
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

@SFSxOI: I'm sure this is a needless post but I thought I would share it anyway. Here's a more simplified version of your code:

Code: Select all

Procedure.s Compare_File_Versions_for_WinUpdate2(In_Compare_Version$)
  Static Known_majver.i = 5
  Static Known_minver.i = 4
  Static Known_bldver.i = 3790
  
  file_majver.i = Val(StringField(In_Compare_Version$, 1, "."))
  file_minver.i = Val(StringField(In_Compare_Version$, 2, "."))
  file_bldver.i = Val(StringField(In_Compare_Version$, 3, "."))
  
  If (file_majver < Known_majver) Or (file_minver < Known_minver) Or (file_bldver < Known_bldver)
    yes_no$ = "bad"
  Else 
    yes_no$ = "good"
  EndIf
  
  ProcedureReturn yes_no$
  
EndProcedure 
It seemed a little easier to see what was being done (from my viewpoint).
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

Using my code above, you could simply do:

Code: Select all

Define.l ver,rev,build,update
ver=5
rev=4
build=2790
update=1000

If CompareVersion(ver,rev,build,update,5,4,3790,1000,3)<0 ;test file version against 5.4.3790.x
 Debug "Use SUS"
Else
 Debug "Use WUA"
EndIf
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

You know, reading that page the solution seems even simpler:
When a call is made to SUS 1.0 by using the WUA API, an HRESULT of WU_E_AU_LEGACYSERVER is returned.
Basically assume it's WUA, and if it fails (the handle returned is #WU_E_AU_LEGACYSERVER) fallback to SUS.
At least that is what I would do.

It seems this is the preferred way, I assume that MicroSoft wish to move everything over to WUA ?

I guess you could call IAutomaticUpdatesResults::LastSearchSuccessDate or sumpt as that is probably information you'd read anyway right?
So if you try that using the WUA API and it returns that special header code simply switch to the legacy API.

PS! Oh and you only have to check this once really, after all if they got the new updater it is unlikely they'll go back to the old. (except unless there is a OS reinstall, in which case your stored mode setting won't be there either and your software will re-check right? :)
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Post by SFSxOI »

Rescator wrote:You know, reading that page the solution seems even simpler:
When a call is made to SUS 1.0 by using the WUA API, an HRESULT of WU_E_AU_LEGACYSERVER is returned.
Basically assume it's WUA, and if it fails (the handle returned is #WU_E_AU_LEGACYSERVER) fallback to SUS.
At least that is what I would do.
yep, thats what I was going to do at first until i found out that even though the return comes back, a remote machine its run against could have crashed as a result (depending on the updates already installed) because it will actually try and execute SUS on the remote machine before you get a return. Its just safer to compare the file versions in this aspect because your not executing anything really on a remote machine. Works OK on local machines though. I still might just take the chance and do it anyway.
Post Reply