00001 #ifndef VERSION_CHECKER_IMPLEMENTATION_FILE
00002 #define VERSION_CHECKER_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "convert_utf.h"
00020 #include "function.h"
00021 #include "guards.h"
00022 #include "istring.h"
00023 #include "portable.h"
00024 #include "version_checker.h"
00025 #include "version_record.h"
00026
00027 #include <stdio.h>
00028
00029 #ifndef BOOT_STRAPPING
00030
00031 #include <__build_version.h>
00032 #else
00033
00034 #define __build_FILE_VERSION "108.420.1024.10008"
00035 #endif
00036
00037 #ifdef _MSC_VER
00038 #include <direct.h>
00039 #include <winver.h>
00040 #endif
00041
00042 #ifdef __WIN32__
00043
00044 #ifdef UNICODE
00045 #define render_ptr(ptr) from_unicode_temp( (UTF16 *) ptr)
00046 #else
00047 #define render_ptr(ptr) ( (char *) ptr)
00048 #endif
00049 #endif
00050
00052
00053 version_checker::version_checker(const istring &library_file_name,
00054 const version &expected_version, const istring &version_complaint)
00055 : _library_file_name(new istring(library_file_name)),
00056 _expected_version(new version(expected_version)),
00057 _version_complaint(new istring(version_complaint))
00058 {}
00059
00060 version_checker::~version_checker()
00061 {
00062 WHACK(_library_file_name);
00063 WHACK(_expected_version);
00064 WHACK(_version_complaint);
00065 }
00066
00067 istring version_checker::text_form() const
00068 {
00069 return istring(class_name()) + ": library_file_name=" + *_library_file_name
00070 + ", expected_version=" + _expected_version->text_form()
00071 + ", complaint_message=" + *_version_complaint;
00072 }
00073
00074 bool version_checker::good_version() const
00075 {
00076 istring version_disabler = portable::env_string("TMP");
00077 version_disabler += "/no_version_check.txt";
00078 FILE *always_okay = fopen(version_disabler.s(), "r");
00079 if (always_okay) {
00080 fclose(always_okay);
00081 return true;
00082 }
00083
00084 version version_found = get_version(*_library_file_name);
00085 if (version_found.compatible(*_expected_version)) return true;
00086 complain_wrong_version(*_library_file_name, *_expected_version,
00087 version_found);
00088 return false;
00089 }
00090
00091 bool version_checker::loaded(const istring &library_file_name)
00092 {
00093 #ifdef __WIN32__
00094 return bool(get_handle(library_file_name) != 0);
00095 #else
00096
00097 return true || library_file_name.t();
00098 #endif
00099 }
00100
00101 void *version_checker::get_handle(const istring &library_file_name)
00102 {
00103 #ifdef __WIN32__
00104 return GetModuleHandle(to_unicode_temp(library_file_name));
00105 #else
00106
00107 return 0 && library_file_name.t();
00108 #endif
00109 }
00110
00111 istring version_checker::get_name(void *to_find)
00112 { return portable::module_name(to_find); }
00113
00114 bool version_checker::retrieve_version_info(const istring &filename,
00115 byte_array &to_fill)
00116 {
00117 to_fill.reset();
00118
00119
00120 int required_size;
00121 #ifdef __WIN32__
00122 u_long module_handle;
00123 required_size = GetFileVersionInfoSize(to_unicode_temp(filename), &module_handle);
00124 #else
00125 required_size = 0 && filename.t();
00126 #endif
00127 if (!required_size) return false;
00128 to_fill.reset(required_size);
00129
00130
00131 bool success = false;
00132 #ifdef __WIN32__
00133 success = GetFileVersionInfo(to_unicode_temp(filename), module_handle,
00134 required_size, to_fill.access());
00135 #else
00136 success = false;
00137 #endif
00138 return success;
00139 }
00140
00141 bool version_checker::get_language(byte_array &version_chunk,
00142 u_short &high, u_short &low)
00143 {
00144 high = 0;
00145 low = 0;
00146 #ifdef __WIN32__
00147
00148 u_int data_size;
00149 void *pointer_to_language_structure;
00150
00151 if (!VerQueryValue(version_chunk.access(),
00152 to_unicode_temp("\\VarFileInfo\\Translation"),
00153 &pointer_to_language_structure, &data_size))
00154 return false;
00155
00156 high = LOWORD(*(unsigned int *)pointer_to_language_structure);
00157 low = HIWORD(*(unsigned int *)pointer_to_language_structure);
00158 #else
00159 high = 0 && version_chunk.length();
00160 low = 0;
00161 #endif
00162
00163 return true;
00164 }
00165
00166 version version_checker::get_version(const istring &filename)
00167 {
00168 #ifdef UNIX
00169
00170
00171
00172
00173
00174
00175
00176 return version(__build_FILE_VERSION);
00177
00178 #endif
00179
00180 byte_array version_info_found(0, NIL);
00181 if (!retrieve_version_info(filename, version_info_found))
00182 return version(0, 0, 0, 0);
00183
00184 u_short high, low;
00185 if (!get_language(version_info_found, high, low))
00186 return version(0, 0, 0, 0);
00187
00188
00189
00190 istring root_key(istring::SPRINTF, "\\StringFileInfo\\%04x%04x", high, low);
00191 istring file_version_key(root_key + istring("\\FileVersion"));
00192
00193 istring version_string;
00194 #ifdef __WIN32__
00195 byte *file_version_pointer;
00196 u_int data_size;
00197 if (!VerQueryValue(version_info_found.access(),
00198 to_unicode_temp(file_version_key),
00199 (LPVOID *)&file_version_pointer, &data_size))
00200 return version(0, 0, 0, 0);
00201 version_string = render_ptr(file_version_pointer);
00202
00203
00204 for (int i = 0; i < version_string.length(); i++) {
00205 if (version_string[i] == ' ') {
00206 version_string.zap(i, i);
00207 i--;
00208 }
00209 }
00210 #else
00211 return version(0, 0, 0, 0);
00212
00213 #endif
00214 return version::from_text(version_string);
00215 }
00216
00217 bool version_checker::get_record(const istring &filename,
00218 version_record &to_fill)
00219 {
00220 to_fill = version_record();
00221 byte_array version_info_found(0, NIL);
00222 if (!retrieve_version_info(filename, version_info_found))
00223 return false;
00224
00225 u_short high, low;
00226 if (!get_language(version_info_found, high, low))
00227 return false;
00228
00229
00230 istring root_key(istring::SPRINTF, "\\StringFileInfo\\%04x%04x", high, low);
00231
00232
00233 bool total_success = true;
00234
00235
00236
00237 #ifdef __WIN32__
00238 u_int data_size;
00239 void *data_pointer;
00240
00241
00242 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00243 + istring("\\FileVersion")), &data_pointer, &data_size))
00244 total_success = false;
00245 else
00246 to_fill.file_version = version::from_text(render_ptr(data_pointer));
00247
00248
00249 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00250 + istring("\\CompanyName")), &data_pointer, &data_size))
00251 total_success = false;
00252 else
00253 to_fill.company_name = render_ptr(data_pointer);
00254
00255
00256 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00257 + istring("\\FileDescription")), &data_pointer, &data_size))
00258 total_success = false;
00259 else
00260 to_fill.description = render_ptr(data_pointer);
00261
00262
00263 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00264 + istring("\\InternalName")), &data_pointer, &data_size))
00265 total_success = false;
00266 else
00267 to_fill.internal_name = render_ptr(data_pointer);
00268
00269
00270 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00271 + istring("\\LegalCopyright")), &data_pointer, &data_size))
00272 total_success = false;
00273 else
00274 to_fill.copyright = render_ptr(data_pointer);
00275
00276
00277 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00278 + istring("\\LegalTrademarks")), &data_pointer, &data_size))
00279 total_success = false;
00280 else
00281 to_fill.trademarks = render_ptr(data_pointer);
00282
00283
00284 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00285 + istring("\\OriginalFilename")), &data_pointer, &data_size))
00286 total_success = false;
00287 else
00288 to_fill.original_name = render_ptr(data_pointer);
00289
00290
00291 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00292 + istring("\\ProductName")), &data_pointer, &data_size))
00293 total_success = false;
00294 else
00295 to_fill.product_name = render_ptr(data_pointer);
00296
00297
00298 if (!VerQueryValue(version_info_found.access(), to_unicode_temp(root_key
00299 + istring("\\ProductVersion")), &data_pointer, &data_size))
00300 total_success = false;
00301 else
00302 to_fill.product_version = version::from_text(render_ptr(data_pointer));
00303 #else
00304
00305 #endif
00306
00307 return total_success;
00308 }
00309
00310 void version_checker::complain_wrong_version(const istring &library_file_name,
00311 const version &expected_version, const version &version_found) const
00312 {
00313 istring to_show("There has been a Version Mismatch: The module \"");
00314
00315 istring module_name = get_name(GET_INSTANCE_HANDLE());
00316 if (!module_name) module_name = "Unknown";
00317 to_show += module_name;
00318 to_show += istring("\" cannot load. This is because the file \"");
00319 to_show += library_file_name;
00320 to_show += istring("\" was expected to have a version of [");
00321
00322 to_show += expected_version.flex_text_form(version::DOTS);
00323
00324 to_show += istring("] but it instead had a version of [");
00325 to_show += version_found.flex_text_form(version::DOTS);
00326
00327 to_show += istring("]. ");
00328 to_show += *_version_complaint;
00329 #ifdef __UNIX__
00330 continuable_error("version checking", "failure", to_show.s());
00331 #elif defined(__WIN32__)
00332 MessageBox(0, to_unicode_temp(to_show),
00333 to_unicode_temp("version_checking::failure"), MB_OK);
00334 #endif
00335 }
00336
00337 void version_checker::complain_cannot_load(const istring &lib_file) const
00338 {
00339 istring to_show("There has been a failure in Version Checking: The file \"");
00340 to_show += lib_file;
00341 to_show += istring("\" could not be loaded or found. ");
00342 to_show += *_version_complaint;
00343 continuable_error("version checking", "loading dll", to_show.s());
00344 }
00345
00346
00347 #endif //VERSION_CHECKER_IMPLEMENTATION_FILE
00348