file version comparison
file version comparison
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?
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):
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 :)
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
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
“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
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
Not the most elegant solution but it's simple, works, and give you a place to start and modify from
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
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 paramsUnfortunately 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 quadspdwyer 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
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.
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.
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.
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:
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
@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:
It seemed a little easier to see what was being done (from my viewpoint).
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 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"
EndIfYou know, reading that page the solution seems even simpler:
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?
Basically assume it's WUA, and if it fails (the handle returned is #WU_E_AU_LEGACYSERVER) fallback to SUS.When a call is made to SUS 1.0 by using the WUA API, an HRESULT of WU_E_AU_LEGACYSERVER is returned.
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?
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.Rescator wrote:You know, reading that page the solution seems even simpler:Basically assume it's WUA, and if it fails (the handle returned is #WU_E_AU_LEGACYSERVER) fallback to SUS.When a call is made to SUS 1.0 by using the WUA API, an HRESULT of WU_E_AU_LEGACYSERVER is returned.
At least that is what I would do.

