Subversion Repositories filter_foundry

Rev

Rev 456 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.         This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.         Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.         Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft
  5.  
  6.         This program is free software; you can redistribute it and/or modify
  7.         it under the terms of the GNU General Public License as published by
  8.         the Free Software Foundation; either version 2 of the License, or
  9.         (at your option) any later version.
  10.  
  11.         This program is distributed in the hope that it will be useful,
  12.         but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.         GNU General Public License for more details.
  15.  
  16.         You should have received a copy of the GNU General Public License
  17.         along with this program; if not, write to the Free Software
  18.         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. #ifndef _CRT_SECURE_NO_WARNINGS
  22. #define _CRT_SECURE_NO_WARNINGS
  23. #endif
  24.  
  25. #include <iostream>
  26. #include <windows.h>
  27. #include <string>
  28. #include <fstream>
  29. #include <vector>
  30.  
  31. typedef struct _PE32 {
  32.         uint32_t magic; // 0x50450000
  33.         IMAGE_FILE_HEADER fileHeader; // COFF Header without Signature
  34.         IMAGE_OPTIONAL_HEADER32 optHeader; // Standard COFF fields, Windows Specific Fields, Data Directories
  35. } PE32;
  36.  
  37. #ifdef UNICODE
  38. typedef std::wstring tstring;
  39. #else
  40. typedef std::string tstring;
  41. #endif
  42.  
  43. int binary_file_string_replace(tstring file_name, const char* asearch, const char* areplace) {
  44.         std::ifstream input(file_name, std::ios::binary);
  45.  
  46.         std::vector<char> buffer((std::istreambuf_iterator<char>(input)), (std::istreambuf_iterator<char>()));
  47.         std::vector<char>::iterator itbegin = buffer.begin();
  48.         std::vector<char>::iterator itend = buffer.end();
  49.  
  50.         if (strlen(asearch) != strlen(areplace)) {
  51.                 printf("Replace value length greater than original!\n");
  52.                 return -1;
  53.         }
  54.         int MAX_BUFFER = strlen(asearch);
  55.  
  56.         char* needed_str = (char*)malloc(MAX_BUFFER);
  57.         if (needed_str == 0) return -1;
  58.         char* replace_str = (char*)malloc(MAX_BUFFER);
  59.         if (replace_str == 0) return -1;
  60.  
  61.         memcpy(needed_str, asearch, MAX_BUFFER);
  62.         memcpy(replace_str, areplace, MAX_BUFFER);
  63.  
  64.         int ifound = 0;
  65.  
  66.         for (auto it = itbegin; it < itend; it++) {
  67.                 if (memcmp(it._Ptr, needed_str, MAX_BUFFER) == 0) {
  68.                         strncpy(it._Ptr, replace_str, MAX_BUFFER);
  69.                         it += MAX_BUFFER - 1; // -1 because it++ will be set on the next loop
  70.                         ifound++;
  71.                 }
  72.         }
  73.  
  74.         if (ifound > 0) {
  75.                 std::ofstream ofile(file_name, std::ios::out | std::ios::binary);
  76.                 ofile.write((char*)&buffer[0], buffer.size() * sizeof(char));
  77.                 ofile.close();
  78.         }
  79.  
  80.         return ifound;
  81. }
  82.  
  83. int binary_file_string_find(tstring file_name, const char* asearch) {
  84.         std::ifstream input(file_name, std::ios::binary);
  85.  
  86.         std::vector<char> buffer((std::istreambuf_iterator<char>(input)), (std::istreambuf_iterator<char>()));
  87.         std::vector<char>::iterator itbegin = buffer.begin();
  88.         std::vector<char>::iterator itend = buffer.end();
  89.  
  90.         int MAX_BUFFER = strlen(asearch);
  91.  
  92.         char* needed_str = (char*)malloc(MAX_BUFFER);
  93.         if (needed_str == 0) return -1;
  94.  
  95.         memcpy(needed_str, asearch, MAX_BUFFER);
  96.  
  97.         int ifound = 0;
  98.  
  99.         for (auto it = itbegin; it < itend; it++) {
  100.                 if (memcmp(it._Ptr, needed_str, MAX_BUFFER) == 0) {
  101.                         it += MAX_BUFFER - 1; // -1 because it++ will be set on the next loop
  102.                         ifound++;
  103.                 }
  104.         }
  105.  
  106.         return ifound;
  107. }
  108.  
  109. void _set_pe_int32(FILE* fptr, size_t fieldoffset, int32_t val) {
  110.         size_t peoffset;
  111.  
  112.         fseek(fptr, 0x3C, SEEK_SET);
  113.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  114.  
  115.         fseek(fptr, (long)peoffset + fieldoffset, SEEK_SET);
  116.         fwrite(&val, sizeof(int32_t), 1, fptr);
  117. }
  118.  
  119. int32_t _get_pe_int32(FILE* fptr, size_t fieldoffset) {
  120.         size_t peoffset;
  121.         int32_t res;
  122.  
  123.         fseek(fptr, 0x3C, SEEK_SET);
  124.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  125.  
  126.         fseek(fptr, (long)peoffset + fieldoffset, SEEK_SET);
  127.         fread(&res, sizeof(int32_t), 1, fptr);
  128.  
  129.         return res;
  130. }
  131.  
  132. bool update_pe_timestamp(LPCTSTR filename, __time32_t timestamp) {
  133.         FILE* fptr = _wfopen(filename, L"rb+");
  134.         if (fptr == NULL) return false;
  135.  
  136.         _set_pe_int32(fptr, /*0x0008*/offsetof(PE32, fileHeader.TimeDateStamp), timestamp);
  137.  
  138.         fclose(fptr);
  139.  
  140.         return true;
  141. }
  142.  
  143. bool openWatcomCosmetics(LPCTSTR filename) {
  144.         if (binary_file_string_find(filename, "Open Watcom") > 0) {
  145.                 FILE* fptr = _wfopen(filename, L"rb+");
  146.                 if (fptr == NULL) return false;
  147.  
  148.                 // Min OS Version 1.11 ... But the actual minimal Windows version is Windows NT 3.11
  149.                 int32_t minOsVersion = _get_pe_int32(fptr, /*0x0040*/offsetof(PE32, optHeader.MajorOperatingSystemVersion));
  150.                 if (minOsVersion == 0x000B0001) {
  151.                         _set_pe_int32(fptr, /*0x0040*/offsetof(PE32, optHeader.MajorOperatingSystemVersion), 0x00000003); // Windows 3.0
  152.                 }
  153.  
  154.                 // Stack reserved cannot be changed with linker option "OPTION STACK=1m" (Rejected https://github.com/open-watcom/open-watcom-v2/issues/780)
  155.                 // It is not required for DLLs, but everybody does it, and I think it is cosmetics to fill these fields, even if not required.
  156.                 _set_pe_int32(fptr, /*0x0060*/offsetof(PE32, optHeader.SizeOfStackReserve), 0x00100000);
  157.                 _set_pe_int32(fptr, /*0x0064*/offsetof(PE32, optHeader.SizeOfStackCommit),  0x00001000);
  158.                 // Heap reserved can be changed with linker option "OPTION HEAP=1m" before beta 21 Dec 2021
  159.                 _set_pe_int32(fptr, /*0x0068*/offsetof(PE32, optHeader.SizeOfHeapReserve),  0x00100000);
  160.                 _set_pe_int32(fptr, /*0x006C*/offsetof(PE32, optHeader.SizeOfHeapCommit),   0x00001000);
  161.  
  162.                 fclose(fptr);
  163.  
  164.                 // 32 bit (OpenWatcom cosmetics): Export table name "FilterFoundry.dll" => "FilterFoundry.8bf"
  165.                 // since OpenWatcom cannot link a 8BF file natively.
  166.                 binary_file_string_replace(filename, "FilterFoundry.dll", "FilterFoundry.8bf");
  167.         }
  168.  
  169.         return true;
  170. }
  171.  
  172. uint32_t calculate_checksum(LPCTSTR filename) {
  173.         //Calculate checksum of image
  174.         // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
  175.         // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
  176.         // Converted from C++ to C by Daniel Marschall
  177.  
  178.         FILE* fptr;
  179.         unsigned long long checksum = 0;
  180.         IMAGE_DOS_HEADER header;
  181.         size_t filesize;
  182.         unsigned long long top;
  183.         unsigned long pe_checksum_pos;
  184.         static const unsigned long checksum_pos_in_optional_headers = 64;
  185.         size_t i;
  186.  
  187.         fptr = _wfopen(filename, L"rb");
  188.         if (fptr == NULL) return 0x00000000;
  189.  
  190.         //Read DOS header
  191.         fseek(fptr, 0, SEEK_SET);
  192.         fread(&header, sizeof(IMAGE_DOS_HEADER), 1, fptr);
  193.  
  194.         //Calculate PE checksum
  195.         fseek(fptr, 0, SEEK_SET);
  196.         top = 0xFFFFFFFF;
  197.         top++;
  198.  
  199.         //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
  200.         //Calculate real PE headers "CheckSum" field position
  201.         //Sum is safe here
  202.         pe_checksum_pos = header.e_lfanew + sizeof(IMAGE_FILE_HEADER) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
  203.  
  204.         //Calculate checksum for each byte of file
  205.         fseek(fptr, 0L, SEEK_END);
  206.         filesize = ftell(fptr);
  207.         fseek(fptr, 0L, SEEK_SET);
  208.         for (i = 0; i < filesize; i += 4)
  209.         {
  210.                 unsigned long dw = 0;
  211.  
  212.                 //Read DWORD from file
  213.                 fread(&dw, sizeof(dw), 1, fptr);
  214.                 //Skip "CheckSum" DWORD
  215.                 if (i == pe_checksum_pos)
  216.                         continue;
  217.  
  218.                 //Calculate checksum
  219.                 checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
  220.                 if (checksum > top)
  221.                         checksum = (checksum & 0xffffffff) + (checksum >> 32);
  222.         }
  223.  
  224.         //Finish checksum
  225.         checksum = (checksum & 0xffff) + (checksum >> 16);
  226.         checksum = (checksum)+(checksum >> 16);
  227.         checksum = checksum & 0xffff;
  228.  
  229.         checksum += (unsigned long)(filesize);
  230.  
  231.         fclose(fptr);
  232.  
  233.         //Return checksum
  234.         return (uint32_t)checksum;
  235. }
  236.  
  237. bool repair_pe_checksum(LPCTSTR filename) {
  238.         FILE* fptr;
  239.  
  240.         uint32_t checksum = calculate_checksum(filename);
  241.         //if (checksum == 0x00000000) return false;
  242.  
  243.         fptr = _wfopen(filename, L"rb+");
  244.         if (fptr == NULL) return false;
  245.  
  246.         _set_pe_int32(fptr, /*0x0058*/offsetof(PE32, optHeader.CheckSum), (int32_t)checksum);
  247.  
  248.         fclose(fptr);
  249.  
  250.         return true;
  251. }
  252.  
  253. bool removeFromFile(LPCTSTR pluginfile, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage) {
  254.         bool bSuccessful = false;
  255.  
  256.         HANDLE hRes = BeginUpdateResource(pluginfile, false);
  257.         if (hRes != NULL) {
  258.                 if (UpdateResource(hRes, lpType, lpName, wLanguage, NULL, 0)) {
  259.                         if (EndUpdateResource(hRes, false)) {
  260.                                 bSuccessful = true;
  261.                         }
  262.                 }
  263.                 else {
  264.                         EndUpdateResource(hRes, true);
  265.                 }
  266.         }
  267.  
  268.         return bSuccessful;
  269. }
  270.  
  271. bool addToFile(LPCTSTR pluginfile, LPCTSTR otherfile, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage) {
  272.         HANDLE hFile;
  273.         DWORD dwFileSize, dwBytesRead;
  274.         LPBYTE lpBuffer;
  275.         bool bSuccessful = false;
  276.  
  277.         hFile = CreateFile(otherfile, GENERIC_READ,
  278.                 0,
  279.                 NULL,
  280.                 OPEN_EXISTING,
  281.                 FILE_ATTRIBUTE_NORMAL,
  282.                 NULL);
  283.  
  284.         if (INVALID_HANDLE_VALUE != hFile)
  285.         {
  286.                 dwFileSize = GetFileSize(hFile, NULL);
  287.  
  288.                 //lpBuffer = new BYTE[dwFileSize];
  289.                 lpBuffer = (LPBYTE)malloc(dwFileSize);
  290.  
  291.                 if (ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE)
  292.                 {
  293.                         HANDLE hRes = BeginUpdateResource(pluginfile, false);
  294.                         if (hRes != NULL) {
  295.                                 if (UpdateResource(hRes, lpType, lpName, wLanguage, lpBuffer, dwFileSize)) {
  296.                                         if (EndUpdateResource(hRes, false)) {
  297.                                                 bSuccessful = true;
  298.                                         }
  299.                                 }
  300.                                 else {
  301.                                         EndUpdateResource(hRes, true);
  302.                                 }
  303.                         }
  304.                 }
  305.  
  306.                 //delete[] lpBuffer;
  307.                 free(lpBuffer);
  308.  
  309.                 CloseHandle(hFile);
  310.         }
  311.  
  312.         return bSuccessful;
  313. }
  314.  
  315.  
  316. int main()
  317. {
  318.         LPCTSTR lpTemplateType = L"TPLT";
  319.         LPCTSTR lpName32Plugin = (LPCTSTR)1032;
  320.         LPCTSTR lpName64Plugin = (LPCTSTR)1064;
  321.         LPCTSTR lpName32Version = (LPCTSTR)3032;
  322.         LPCTSTR lpName64Version = (LPCTSTR)3064;
  323.         LPCTSTR lpName32Pipl = (LPCTSTR)16032;
  324.         LPCTSTR lpName64Pipl = (LPCTSTR)16064;
  325.         WORD wLanguageEnUs = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); // 1033 en-US
  326.         WORD wLanguageNeutral = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); // 0 Neutral
  327.  
  328.         LPCTSTR file32in = L"in\\FilterFoundry.8bf";
  329.         LPCTSTR file64in = L"in\\FilterFoundry64.8bf";
  330.         LPCTSTR file32out = L"out\\FilterFoundry.8bf";
  331.         LPCTSTR file64out = L"out\\FilterFoundry64.8bf";
  332.         LPCTSTR file32tmp = L"FilterFoundry.tmp";
  333.         LPCTSTR file64tmp = L"FilterFoundry64.tmp";
  334.  
  335.         // 1a. Copy 32 "IN" to 32 "TMP", and 64 "IN" to 64 "TMP"
  336.         {
  337.                 if (!CopyFile(file32in, file32tmp, false)) {
  338.                         DeleteFile(file32out);
  339.                         DeleteFile(file64out);
  340.                         printf("Error: Copyfile 32in > 32tmp\n");
  341.                         return 1;
  342.                 }
  343.  
  344.                 if (!CopyFile(file64in, file64tmp, false)) {
  345.                         DeleteFile(file32out);
  346.                         DeleteFile(file64out);
  347.                         printf("Error: Copyfile 64in > 64tmp\n");
  348.                         return 1;
  349.                 }
  350.         }
  351.  
  352.         // 1b. Copy 32 "IN" to 32 "OUT", and 64 "IN" to 64 "OUT" (will be edited later)
  353.         {
  354.                 if (!CopyFile(file32in, file32out, false)) {
  355.                         DeleteFile(file32out);
  356.                         DeleteFile(file64out);
  357.                         printf("Error: Copyfile 32in > 32out\n");
  358.                         return 1;
  359.                 }
  360.  
  361.                 if (!CopyFile(file64in, file64out, false)) {
  362.                         DeleteFile(file32out);
  363.                         DeleteFile(file64out);
  364.                         printf("Error: Copyfile 64in > 64out\n");
  365.                         return 1;
  366.                 }
  367.         }
  368.  
  369.         // 2. Remove any template residues at 32/64 "TMP", since they are only used for building
  370.         //    "TMP" is our "standalone plugin skelleton"
  371.         // TODO: Also remove build dialogs, cursors and icons (like done in make_win.c)?
  372.         {
  373.                 // Remove TPLT 1 (Manifest template)
  374.                 removeFromFile(file32tmp, lpTemplateType, MAKEINTRESOURCE(1), wLanguageNeutral);
  375.                 removeFromFile(file64tmp, lpTemplateType, MAKEINTRESOURCE(1), wLanguageNeutral);
  376.  
  377.                 // Remove TPLT 1032/1064 (8BF included)
  378.                 removeFromFile(file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs);
  379.                 removeFromFile(file32tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs);
  380.                 removeFromFile(file64tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs);
  381.                 removeFromFile(file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs);
  382.  
  383.                 // Remove TPLT 3032/3064 (Versioninfo included)
  384.                 removeFromFile(file32tmp, lpTemplateType, lpName32Version, wLanguageEnUs);
  385.                 removeFromFile(file32tmp, lpTemplateType, lpName64Version, wLanguageEnUs);
  386.                 removeFromFile(file64tmp, lpTemplateType, lpName32Version, wLanguageEnUs);
  387.                 removeFromFile(file64tmp, lpTemplateType, lpName64Version, wLanguageEnUs);
  388.  
  389.                 // Remove TPLT 16032/16064 (PIPL template)
  390.                 removeFromFile(file32tmp, lpTemplateType, lpName32Pipl, wLanguageNeutral);
  391.                 removeFromFile(file32tmp, lpTemplateType, lpName64Pipl, wLanguageNeutral);
  392.                 removeFromFile(file64tmp, lpTemplateType, lpName32Pipl, wLanguageNeutral);
  393.                 removeFromFile(file64tmp, lpTemplateType, lpName64Pipl, wLanguageNeutral);
  394.         }
  395.  
  396.         // Do some cosmetics to OpenWatcom binaries
  397.         openWatcomCosmetics(file32tmp);
  398.         openWatcomCosmetics(file32out);
  399.  
  400.         // 3. Update timestamp of 32/64 "TMP"
  401.         {
  402.                 if (!update_pe_timestamp(file32tmp, (__time32_t)time(0))) {
  403.                         DeleteFile(file32out);
  404.                         DeleteFile(file64out);
  405.                         printf("Error: Update TMP timestamp 32\n");
  406.                         return 1;
  407.                 }
  408.  
  409.                 if (!update_pe_timestamp(file64tmp, (__time32_t)time(0))) {
  410.                         DeleteFile(file32out);
  411.                         DeleteFile(file64out);
  412.                         printf("Error: Update TMP timestamp 64\n");
  413.                         return 1;
  414.                 }
  415.         }
  416.  
  417.         // 4. Repair checksums of 32/64 "TMP"
  418.         {
  419.                 if (!repair_pe_checksum(file32tmp)) {
  420.                         DeleteFile(file32out);
  421.                         DeleteFile(file64out);
  422.                         printf("Error: Repair TMP checksum 32\n");
  423.                         return 1;
  424.                 }
  425.                 if (!repair_pe_checksum(file64tmp)) {
  426.                         DeleteFile(file32out);
  427.                         DeleteFile(file64out);
  428.                         printf("Error: Repair TMP checksum 64\n");
  429.                         return 1;
  430.                 }
  431.         }
  432.  
  433.         // 6. Add 32/64 "TMP" to 64/32 "OUT" ("criss-cross")
  434.         {
  435.                 if (!addToFile(file32out, file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs)) {
  436.                         DeleteFile(file32out);
  437.                         DeleteFile(file64out);
  438.                         printf("Error: Add 32 to 32\n");
  439.                         return 1;
  440.                 }
  441.                 if (!addToFile(file32out, file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs)) {
  442.                         DeleteFile(file32out);
  443.                         DeleteFile(file64out);
  444.                         printf("Error: Add 64 to 32\n");
  445.                         return 1;
  446.                 }
  447.  
  448.                 if (!addToFile(file64out, file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs)) {
  449.                         DeleteFile(file32out);
  450.                         DeleteFile(file64out);
  451.                         printf("Error: Add 32 to 64\n");
  452.                         return 1;
  453.                 }
  454.  
  455.                 if (!addToFile(file64out, file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs)) {
  456.                         DeleteFile(file32out);
  457.                         DeleteFile(file64out);
  458.                         printf("Error: Add 64 to 64\n");
  459.                         return 1;
  460.                 }
  461.         }
  462.  
  463.         // 7a. Read Version Info from 32 bit "TMP", and copy it to 32/64 "OUT" template
  464.         {
  465.                 HMODULE lib = LoadLibraryEx(file32tmp, NULL, LOAD_LIBRARY_AS_DATAFILE);
  466.                 if (!lib) {
  467.                         printf("Loadlib failed at versioninfo TPLT 32");
  468.                         return 1;
  469.                 }
  470.                 HRSRC resinfo = FindResource(lib, MAKEINTRESOURCE(1), RT_VERSION);
  471.                 if (!resinfo) {
  472.                         printf("FindResource failed at versioninfo TPLT 32");
  473.                         return 1;
  474.                 }
  475.                 size_t cbVersionInfo = SizeofResource(lib, resinfo);
  476.                 HGLOBAL hvinfo = LoadResource(lib, resinfo);
  477.                 if (!hvinfo) {
  478.                         printf("LoadResource failed at versioninfo TPLT 32");
  479.                         return 1;
  480.                 }
  481.                 char* vinfo = (char*)LockResource(hvinfo);
  482.                 char* vinfocpy = (char*)malloc(cbVersionInfo);
  483.                 if (vinfocpy == NULL) return 1;
  484.                 memcpy(vinfocpy, vinfo, cbVersionInfo);
  485.                 UnlockResource(hvinfo);
  486.                 FreeLibrary(lib);
  487.  
  488.                 // Write Version info to TPLT Resource of 32 bit "OUT"
  489.  
  490.                 HANDLE hupd = BeginUpdateResource(file32out, false);
  491.                 UpdateResource(hupd, TEXT("TPLT"), lpName32Version, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), vinfocpy, cbVersionInfo);
  492.                 EndUpdateResource(hupd, false);
  493.  
  494.                 // Write Version info to TPLT Resource of 64 bit "OUT"
  495.  
  496.                 hupd = BeginUpdateResource(file64out, false);
  497.                 UpdateResource(hupd, TEXT("TPLT"), lpName32Version, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), vinfocpy, cbVersionInfo);
  498.                 EndUpdateResource(hupd, false);
  499.  
  500.                 // Free memory
  501.  
  502.                 free(vinfocpy);
  503.         }
  504.  
  505.         // 7b. Read Version Info from 64 bit "TMP", and copy it to 32/64 "OUT" template
  506.         {
  507.                 HMODULE lib = LoadLibraryEx(file64tmp, NULL, LOAD_LIBRARY_AS_DATAFILE);
  508.                 if (!lib) {
  509.                         printf("Loadlib failed at versioninfo TPLT 64");
  510.                         return 1;
  511.                 }
  512.                 HRSRC resinfo = FindResource(lib, MAKEINTRESOURCE(1), RT_VERSION);
  513.                 if (!resinfo) {
  514.                         printf("FindResource failed at versioninfo TPLT 64");
  515.                         return 1;
  516.                 }
  517.                 size_t cbVersionInfo = SizeofResource(lib, resinfo);
  518.                 HGLOBAL hvinfo = LoadResource(lib, resinfo);
  519.                 if (!hvinfo) {
  520.                         printf("LoadResource failed at versioninfo TPLT 64");
  521.                         return 1;
  522.                 }
  523.                 char* vinfo = (char*)LockResource(hvinfo);
  524.                 char* vinfocpy = (char*)malloc(cbVersionInfo);
  525.                 if (vinfocpy == NULL) return 1;
  526.                 memcpy(vinfocpy, vinfo, cbVersionInfo);
  527.                 UnlockResource(hvinfo);
  528.                 FreeLibrary(lib);
  529.  
  530.                 // Write Version info to TPLT Resource of 32 bit "OUT"
  531.  
  532.                 HANDLE hupd = BeginUpdateResource(file32out, false);
  533.                 UpdateResource(hupd, TEXT("TPLT"), lpName64Version, 1033, vinfocpy, cbVersionInfo);
  534.                 EndUpdateResource(hupd, false);
  535.  
  536.                 // Write Version info to TPLT Resource of 64 bit "OUT"
  537.  
  538.                 hupd = BeginUpdateResource(file64out, false);
  539.                 UpdateResource(hupd, TEXT("TPLT"), lpName64Version, 1033, vinfocpy, cbVersionInfo);
  540.                 EndUpdateResource(hupd, false);
  541.  
  542.                 // Free memory
  543.  
  544.                 free(vinfocpy);
  545.         }
  546.  
  547.         // 8. Delete 32/64 "TMP"
  548.         {
  549.                 DeleteFile(file32tmp);
  550.                 DeleteFile(file64tmp);
  551.         }
  552.  
  553.         // 9. Update timestamp of 32/64 "OUT"
  554.         {
  555.                 if (!update_pe_timestamp(file32out, (__time32_t)time(0))) {
  556.                         DeleteFile(file32out);
  557.                         DeleteFile(file64out);
  558.                         printf("Error: Update OUT timestamp 32\n");
  559.                         return 1;
  560.                 }
  561.  
  562.                 if (!update_pe_timestamp(file64out, (__time32_t)time(0))) {
  563.                         DeleteFile(file32out);
  564.                         DeleteFile(file64out);
  565.                         printf("Error: Update OUT timestamp 64\n");
  566.                         return 1;
  567.                 }
  568.         }
  569.  
  570.         // 10. Repair checksums of 32/64 "OUT"
  571.         {
  572.                 if (!repair_pe_checksum(file32out)) {
  573.                         DeleteFile(file32out);
  574.                         DeleteFile(file64out);
  575.                         printf("Error: Repair OUT checksum 32\n");
  576.                         return 1;
  577.                 }
  578.                 if (!repair_pe_checksum(file64out)) {
  579.                         DeleteFile(file32out);
  580.                         DeleteFile(file64out);
  581.                         printf("Error: Repair OUT checksum 64\n");
  582.                         return 1;
  583.                 }
  584.         }
  585.  
  586.         // 11. All done!
  587.  
  588.         printf("All OK!\n");
  589.         return 0;
  590. }
  591.