| 463 | } |
| 464 | |
| 465 | USHORT PatchVersion(const TEXT* filename, DWORD verMS, err_handler_t err_handler) |
| 466 | { |
| 467 | /************************************** |
| 468 | * |
| 469 | * P a t c h V e r s i o n |
| 470 | * |
| 471 | ************************************** |
| 472 | * |
| 473 | * Functional description |
| 474 | * Patches the FileVersion and ProductVersion of a DLL whose full |
| 475 | * path is given as "filename" parameter. The function only updates the major |
| 476 | * and minor version numbers, leaving the sub-minor and build intact. |
| 477 | * We typically use this trick to build a GDS32.DLL whose version is 6.3 |
| 478 | * from our FBCLIENT.DLL whose version is 1.5. |
| 479 | * |
| 480 | * The politically correct way (speaking of Win32 API) of changing the |
| 481 | * version info, should involve using GetFileVersionInfo() and VerQueryValue() |
| 482 | * to read the existing version resource, and using BeginUpdateResource(), |
| 483 | * UpdateResource() and EndUpdateResource() to actually update the dll file. |
| 484 | * Unfortunately those last 3 APIs are not implemented on Win95/98/Me. |
| 485 | * |
| 486 | * Therefore this function proceeds by straight hacking of the dll file. |
| 487 | * This is not intellectually satisfactory, but does work perfectly and |
| 488 | * fits the bill. |
| 489 | * |
| 490 | **************************************/ |
| 491 | |
| 492 | HANDLE hfile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, |
| 493 | 0 /* FILE_SHARE_NONE */, 0, OPEN_EXISTING, |
| 494 | FILE_FLAG_SEQUENTIAL_SCAN, 0); |
| 495 | if (hfile == INVALID_HANDLE_VALUE) |
| 496 | return (*err_handler) (GetLastError(), "CreateFile()"); |
| 497 | |
| 498 | DWORD fsize = GetFileSize(hfile, 0); |
| 499 | |
| 500 | HANDLE hmap = CreateFileMapping(hfile, 0, |
| 501 | PAGE_READWRITE | SEC_COMMIT, 0, 0, 0); |
| 502 | if (hmap == 0) |
| 503 | { |
| 504 | ULONG werr = GetLastError(); |
| 505 | CloseHandle(hfile); |
| 506 | return (*err_handler) (werr, "CreateFileMapping()"); |
| 507 | } |
| 508 | |
| 509 | BYTE* mem = static_cast<BYTE*>(MapViewOfFile(hmap, |
| 510 | FILE_MAP_WRITE, 0, 0, 0)); |
| 511 | if (mem == 0) |
| 512 | { |
| 513 | ULONG werr = GetLastError(); |
| 514 | CloseHandle(hmap); |
| 515 | CloseHandle(hfile); |
| 516 | return (*err_handler) (werr, "MapViewOfFile()"); |
| 517 | } |
| 518 | |
| 519 | // This is a "magic value" that will allow locating the version info. |
| 520 | // Windows itself does something equivalent internally. |
| 521 | const BYTE lookup[] = |
| 522 | { |