From 170bc1e725d52b2b5398527b32cca68579f8d891 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Sat, 2 Jan 2016 13:43:02 +0000 Subject: IconPatcher initial commit (thanks dracosha) git-svn-id: http://svn.miranda-ng.org/main/trunk@15987 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- tools/IconPatcher/IconPatcher.exe | Bin 0 -> 926394 bytes tools/IconPatcher/IconPatcher_v.1.0.iss | 1119 ++++++++++++++++++++++++++++ tools/IconPatcher/{res}/7-zip32.dll | Bin 0 -> 637952 bytes tools/IconPatcher/{res}/done.ico | Bin 0 -> 790 bytes tools/IconPatcher/{res}/error.ico | Bin 0 -> 790 bytes tools/IconPatcher/{res}/icon.ico | Bin 0 -> 5430 bytes tools/IconPatcher/{res}/iconpatcher_en.isl | 37 + tools/IconPatcher/{res}/iconpatcher_ru.isl | 37 + tools/IconPatcher/{res}/plugin.ico | Bin 0 -> 1150 bytes tools/IconPatcher/{res}/skip.ico | Bin 0 -> 790 bytes 10 files changed, 1193 insertions(+) create mode 100644 tools/IconPatcher/IconPatcher.exe create mode 100644 tools/IconPatcher/IconPatcher_v.1.0.iss create mode 100644 tools/IconPatcher/{res}/7-zip32.dll create mode 100644 tools/IconPatcher/{res}/done.ico create mode 100644 tools/IconPatcher/{res}/error.ico create mode 100644 tools/IconPatcher/{res}/icon.ico create mode 100644 tools/IconPatcher/{res}/iconpatcher_en.isl create mode 100644 tools/IconPatcher/{res}/iconpatcher_ru.isl create mode 100644 tools/IconPatcher/{res}/plugin.ico create mode 100644 tools/IconPatcher/{res}/skip.ico (limited to 'tools') diff --git a/tools/IconPatcher/IconPatcher.exe b/tools/IconPatcher/IconPatcher.exe new file mode 100644 index 0000000000..b09aef32ce Binary files /dev/null and b/tools/IconPatcher/IconPatcher.exe differ diff --git a/tools/IconPatcher/IconPatcher_v.1.0.iss b/tools/IconPatcher/IconPatcher_v.1.0.iss new file mode 100644 index 0000000000..f08f1689d8 --- /dev/null +++ b/tools/IconPatcher/IconPatcher_v.1.0.iss @@ -0,0 +1,1119 @@ +; Параметры комстроки: +; /BIN = "путь к Miranda32/64.exe". Путь к exe-файлу миранды, относительно него будут сопоставляться файлы из архива с ресурсами с файлами миранды. +; /ARC = имя архива без расширения, например, /ARC=nova +; /RES = список папок из архива для обработки, например, /RES=icons,plugins,root. Это то, что будет отмечено в интерфейсе патчера. Если нужно все отметить, то /RES либо опустить, либо /RES=*. +; Структура папок в архивах, например, icons\Proto_ICQ\*.ico, означает, что по пути, указанному в /BIN должна быть папка icons, в ней файл Proto_ICQ (возможных расширений .exe, .dll, .mir). +; Папка root для красоты и не повторяет оригинальную структуру программы, в ней только ресурсы для exe миранды. + +#define AppName "IconPatcher" +#define AppFullName "Miranda icon patcher" +#define AppVerName "1.0" +#define AppPublisher "El Sanchez" + +[Setup] +AppName={#AppName} +AppVerName={#AppVerName} +DefaultDirName={tmp} +CreateAppDir=no +Uninstallable=no +CreateUninstallRegKey=no +DisableWelcomePage=yes +DisableReadyPage=yes +DisableFinishedPage=yes +ShowLanguageDialog=no +OutputBaseFilename={#AppName} +SetupIconFile={res}\icon.ico +VersionInfoVersion={#AppVerName} +VersionInfoDescription={#AppFullName} +AppPublisher={#AppPublisher} +PrivilegesRequired=lowest +IconResource=plugin:{res}\plugin.ico|done:{res}\done.ico|skip:{res}\skip.ico|error:{res}\error.ico + +[Languages] +Name: en; MessagesFile: compiler:default.isl,{res}\iconpatcher_en.isl +Name: ru; MessagesFile: compiler:Languages\russian.isl,{res}\iconpatcher_ru.isl + +[Files] +Source: {res}\7-zip32.dll; Flags: dontcopy + +[Code] +#define A = (Defined UNICODE) ? "W" : "A" +const + SZ_ERROR = 1; + SZ_DLLERROR = 3; + LOAD_LIBRARY_AS_DATAFILE = $2; + RT_ICON = 3; + RT_GROUP_ICON = (RT_ICON + 11); + GENERIC_READ = $80000000; + FILE_SHARE_READ = $0001; + OPEN_EXISTING = $0003; + INVALID_HANDLE_VALUE = (-1); + PAGE_READONLY = $0002; + FILE_MAP_READ = $0004; + GWL_STYLE = (-16); + GWL_EXSTYLE = (-20); + TVS_CHECKBOXES = $0100; + WS_EX_COMPOSITED = $02000000; + TV_FIRST = $1100; + TVM_GETIMAGELIST = (TV_FIRST + 8); + TVSIL_STATE = 2; + ILC_COLOR32 = $0020; + SHGFI_ICON = $0100; + SHGFI_SMALLICON = $0001; + SHGFI_OPENICON = $0002; + DI_NORMAL = $3; + IMAGE_ICON = 1; + BI_RGB = $0; + DIB_RGB_COLORS = 0; + +type + INDIVIDUALINFO = record + dwOriginalSize: DWORD; + dwCompressedSize: DWORD; + dwCRC: DWORD; + uFlag: UINT; + uOSType: UINT; + wRatio: WORD; + wDate: WORD; + wTime: WORD; + #ifdef UNICODE + szFileName: array [0..512] of AnsiChar; + #else + szFileName: array [0..512] of Char; + #endif + dummy1: array [0..2] of Byte; + #ifdef UNICODE + szAttribute: array [0..7] of AnsiChar; + szMode: array [0..7] of AnsiChar; + #else + szAttribute: array [0..7] of Char; + szMode: array [0..7] of Char; + #endif + end; + + SHFILEINFO = record + hIcon: HICON; + iIcon: Integer; + dwAttributes: DWORD; + szDisplayName: array [0..259] of Char; + szTypeName: array [0..79] of Char; + end; + + BITMAPINFOHEADER = record + biSize: DWORD; + biWidth: Longint; + biHeight: Longint; + biPlanes: WORD; + biBitCount: WORD; + biCompression: DWORD; + biSizeImage: DWORD; + biXPelsPerMeter: Longint; + biYPelsPerMeter: Longint; + biClrUsed: DWORD; + biClrImportant: DWORD; + end; + + RGBQUAD = record + rgbBlue: Byte; + rgbGreen: Byte; + rgbRed: Byte; + rgbReserved: Byte; + end; + + BITMAPINFO = record + bmiHeader: BITMAPINFOHEADER; + bmiColors: array of RGBQUAD; + end; + + ICONDIRENTRY = record + bWidth: Byte; + bHeight: Byte; + bColorCount: Byte; + bReserved: Byte; + wPlanes: WORD; + wBitCount: WORD; + dwBytesInRes: DWORD; + dwImageOffset: DWORD; + end; + + ICONDIR = record + idReserved: WORD; + idType: WORD; + idCount: WORD; + idEntries: array [0..0] of ICONDIRENTRY; + end; + + GRPICONDIRENTRY = record + bWidth: Byte; + bHeight: Byte; + bColorCount: Byte; + bReserved: Byte; + wPlanes: WORD; + wBitCount: WORD; + dwBytesInRes: DWORD; + nID: WORD; + end; + + GRPICONDIR = record + idReserved: WORD; + idType: WORD; + idCount: WORD; + idEntries: array [0..255] of GRPICONDIRENTRY; + end; + + TUpdateResItem = record + szName: string; + wLanguage: WORD; + lpIconDir: Longint; + end; + + TUpdateResHelper = record + Items: array of TUpdateResItem; + IconList: TStringList; + end; + +function SevenZipOpenArchive(const hwnd: HWND; szFileName: AnsiString; const dwMode: DWORD): THandle; external 'SevenZipOpenArchive@files:7-zip32.dll stdcall'; +function SevenZipCloseArchive(harc: THandle): Integer; external 'SevenZipCloseArchive@files:7-zip32.dll stdcall'; +function SevenZipFindFirst(harc: THandle; szWildName: AnsiString; var lpSubInfo: INDIVIDUALINFO): Integer; external 'SevenZipFindFirst@files:7-zip32.dll stdcall'; +function SevenZipFindNext(harc: THandle; var lpSubInfo: INDIVIDUALINFO): Integer; external 'SevenZipFindNext@files:7-zip32.dll stdcall'; +function SevenZipCheckArchive(szFileName: AnsiString; const iMode: Integer): BOOL; external 'SevenZipCheckArchive@files:7-zip32.dll stdcall'; +function SevenZip(const hwnd: HWND; szCmdLine, szOutput: AnsiString; const dwSize: DWORD): Integer; external 'SevenZip@files:7-zip32.dll stdcall'; +function SevenZipSetOwnerWindowEx(hwnd: HWND; lpArcProc: Longint): BOOL; external 'SevenZipSetOwnerWindowEx@files:7-zip32.dll stdcall'; +function SevenZipKillOwnerWindowEx(hwnd: HWND): BOOL; external 'SevenZipKillOwnerWindowEx@files:7-zip32.dll stdcall'; + +function RtlMoveMemoryWORD(var Destination: WORD; const Source: Longint; len: Integer): Integer; external 'RtlMoveMemory@kernel32.dll stdcall'; +function RtlMoveMemoryGRPIDE(var Destination: GRPICONDIRENTRY; const Source: Longint; len: Integer): Integer; external 'RtlMoveMemory@kernel32.dll stdcall'; +function RtlMoveMemoryIDE(var Destination: ICONDIRENTRY; const Source: Longint; len: Integer): Integer; external 'RtlMoveMemory@kernel32.dll stdcall'; +function RtlMoveMemoryBI(var Destination: BITMAPINFOHEADER; const Source: Longint; len: Integer): Integer; external 'RtlMoveMemory@kernel32.dll stdcall'; + +function LoadLibraryEx(lpFileName: string; hFile: THandle; dwFlags: DWORD): THandle; external 'LoadLibraryEx{#A}@kernel32.dll stdcall'; +function FreeLibrary(hModule: THandle): BOOL; external 'FreeLibrary@kernel32.dll stdcall'; + +function BeginUpdateResource(pFileName: string; bDeleteExistingResources: BOOL): THandle; external 'BeginUpdateResource{#A}@kernel32.dll stdcall'; +function UpdateResource(hUpdate: THandle; lpType, lpName: Longint; wLanguage: WORD; lpData: Longint; cbData: DWORD): BOOL; external 'UpdateResource{#A}@kernel32.dll stdcall'; +function UpdateResourcePtr(hUpdate: THandle; lpType, lpName: Longint; wLanguage: WORD; var lpData: GRPICONDIR; cbData: DWORD): BOOL; external 'UpdateResource{#A}@kernel32.dll stdcall'; +function EndUpdateResource(hUpdate: THandle; fDiscard: BOOL): BOOL; external 'EndUpdateResource{#A}@kernel32.dll stdcall'; + +function EnumResourceNames(hModule: THandle; lpszType, lpEnumFunc, lParam: Longint): BOOL; external 'EnumResourceNames{#A}@kernel32.dll stdcall'; +function EnumResourceLanguages(hModule: THandle; lpType, lpName, lpEnumFunc, lParam: Longint): BOOL; external 'EnumResourceLanguages{#A}@kernel32.dll stdcall'; + +function LoadImage(hInst: THandle; lpszName: string; uType: UINT; cxDesired, cyDesired: Integer; fuLoad: UINT): THandle; external 'LoadImage{#A}@user32.dll stdcall'; +function LoadResource(hModule, hResInfo: THandle): THandle; external 'LoadResource@kernel32.dll stdcall'; +function LockResource(hResData: THandle): Longint; external 'LockResource@kernel32.dll stdcall'; +function FindResource(hModule: THandle; lpName, lpType: Longint): THandle; external 'FindResource{#A}@kernel32.dll stdcall'; + +function CreateFile(lpFileName: string; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: Longint; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; external 'CreateFile{#A}@kernel32.dll stdcall'; +function CreateFileMapping(hFile: THandle; lpAttributes: Longint; flProtect, dwMaximumSizeHigh, dwMaximumSizeLow: DWORD; lpName: String): THandle; external 'CreateFileMapping{#A}@kernel32.dll stdcall'; +function MapViewOfFile(hFileMappingObject: THandle; dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap: DWORD): Longint; external 'MapViewOfFile@kernel32.dll stdcall'; +function UnmapViewOfFile(lpBaseAddress: Longint): BOOL; external 'UnmapViewOfFile@kernel32.dll stdcall'; +function CloseHandle(hObject: THandle): BOOL; external 'CloseHandle@kernel32.dll stdcall'; + +function GetWindowLong(hWnd: HWND; nIndex: Integer): Longint; external 'GetWindowLong{#A}@user32.dll stdcall'; +function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint; external 'SetWindowLong{#A}@user32.dll stdcall'; + +function ImageList_Create(cx, cy: Integer; flags: UINT; cInitial, cGrow: Integer): HIMAGELIST; external 'ImageList_Create@comctl32.dll stdcall'; +function ImageList_Add(himl: HIMAGELIST; hbmImage, hbmMask: HBITMAP): Integer; external 'ImageList_Add@comctl32.dll stdcall'; +function ImageList_GetIconSize(himl: HIMAGELIST; out cx, cy: Integer): BOOL; external 'ImageList_GetIconSize@comctl32.dll stdcall'; + +function SHGetFileInfo(pszPath: string; dwFileAttributes: DWORD; var psfi: SHFILEINFO; cbFileInfo, uFlags: UINT): DWORD; external 'SHGetFileInfo{#A}@shell32.dll stdcall'; +function DestroyIcon(hIcon: HICON): BOOL; external 'DestroyIcon@user32.dll stdcall'; +function DrawIconEx(hdc: Longint; xLeft, yTop: Integer; hIcon: HICON; cxWidth, cyWidth: Integer; istepIfAniCur: UINT; hbrFlickerFreeDraw: Longint; diFlags: UINT): BOOL; external 'DrawIconEx@user32.dll stdcall'; + +function CreateDIBSection(hdc: THandle; const pbmi: BITMAPINFO; iUsage: UINT; out ppvBits: Longint; hSection: THandle; dwOffset: DWORD): HBITMAP; external 'CreateDIBSection@gdi32.dll stdcall'; + +function ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL; external 'ShowWindow@user32.dll stdcall'; + +var + UpdateForm: TForm; + StatusBar: TStatusBar; + ProgressBar: TNewProgressBar; + BrowseButton: TNewButton; + BrowseEdit: TEdit; + SelectArchiveComboBox: TComboBox; + SelectResButton, PatchButton: TNewButton; + SelectResTreeView: TTreeView; + ResourcesList: TStringList; + ResHelper: TUpdateResHelper; + +/////////////////////////////////////////////////////////////////// +function CharArrayToString(const AChar: array of AnsiChar): string; +var + i: Integer; +begin + Result := ''; + while AChar[i] <> #0 do + begin + Insert(AChar[i], Result, Length(Result) + 1); + i := i + 1; + end; +end; + +/////////////////////////////////////////////////////// +function IsParameter(const Parameter: string): Boolean; +var + i: Integer; +begin + for i := 2 to ParamCount do + if CompareText(Parameter, ParamStr(i)) = 0 then + begin + Result := True; + Break; + end; +end; + +////////////////////////////// +function DisplayHelp: Boolean; +var + i: Integer; +begin + for i := 2 to ParamCount do + if CompareText('/?', ParamStr(i)) = 0 then + begin + MsgBoxEx(0, FmtMessage(CustomMessage('cmHelpMsg'), [ExtractFileName(ExpandConstant('{srcexe}'))]), FmtMessage(CustomMessage('cmHelpMsgCaption'), ['{#AppName}']), MB_OK, Application.Icon.Handle, 0); + Result := True; + Break; + end; +end; + +////////////////////////////// +function CheckSource: Boolean; +var + FR: TFindRec; + FileName: AnsiString; + hArc: THandle; + lpSubInfo: INDIVIDUALINFO; +begin + Log(CustomMessage('cmLogFindResource7ZipFile1a')); + ResourcesList := TStringList.Create; + ResourcesList.Sorted := True; + if FindFirst(ExpandConstant('{src}\*.7z'), FR) then + try + repeat + FileName := ExpandConstant(Format('{src}\%s', [FR.Name])); + if SevenZipCheckArchive(FileName, 0) then + begin + Log(FmtMessage(CustomMessage('cmLogResource7ZipFile'), [FR.Name])); + ResourcesList.AddObject(FileName, TStringList.Create); + with TStringList(ResourcesList.Objects[ResourcesList.Count - 1] as TStringList) do + begin + Sorted := True; + hArc := SevenZipOpenArchive(0, ResourcesList[ResourcesList.Count - 1], 0); + if hArc <> 0 then + begin + if SevenZipFindFirst(hArc, '*.ico', lpSubInfo) = 0 then + begin + Add(CharArrayToString(lpSubInfo.szFileName)); + while SevenZipFindNext(hArc, lpSubInfo) = 0 do + Add(CharArrayToString(lpSubInfo.szFileName)); + end; + SevenZipCloseArchive(hArc); + end; + Log(FmtMessage(CustomMessage('cmLogResource7ZipFileContent'), [CommaText])); + end; + end; + until not FindNext(FR); + finally + FindClose(FR); + end; + Result := (ResourcesList.Count > 0); + if not Result then + MsgBox(CustomMessage('cmFileNotFound'), mbError, MB_OK); + Log(CustomMessage('cmLogFindResource7ZipFile1b')); +end; + +////////////////////////////////////////////////////////////////////////////////// +function ExtractArchive(const FileName, OutputDir, AddParam: AnsiString): Integer; +var + Params: AnsiString; +begin + Result := SZ_ERROR; + Params := Format('e "%s" -o"%s" "%s" -y -hide', [FileName, OutputDir, AddParam]); + CharToOemBuff(Params); + try + SevenZipSetOwnerWindowEx(UpdateForm.Handle, 0); + Result := SevenZip(UpdateForm.Handle, Params, '', 0); + finally + SevenZipKillOwnerWindowEx(UpdateForm.Handle); + except + Result := SZ_DLLERROR; + end; +end; + +/////////////////////////////////// +function GetFreeIconIndex: Integer; +var + i: Integer; +begin + Result := 1; + while ResHelper.IconList.Find(Padz(IntToStr(Result), 5), i) do + Inc(Result); + ResHelper.IconList.Add(Padz(IntToStr(Result), 5)); +end; + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function EnumResLangProc(hModule: THandle; lpszType, lpszName: Longint; wIDLanguage: WORD; lParam: Longint): BOOL; +begin + ResHelper.Items[lParam].wLanguage := wIDLanguage; + Result := False; +end; + +////////////////////////////////////////////////////////////////////////////////////// +function EnumResNameProc(hModule: THandle; lpszType, lpszName, lParam: Longint): BOOL; +var + ResName: string; + bUpdate: Boolean; + R, Res, hFile, hMapObject: THandle; + lpGroupIconDir: Longint; + idCount: WORD; + grpide: GRPICONDIRENTRY; + i, n: Integer; +begin + Result := True; + + { resource name } + if lpszName shr $10 > 0 then + ResName := CastIntegerToString(lpszName) + else + ResName := IntToStr(lpszName); + bUpdate := FileExists(ExpandConstant(Format('{tmp}\resources\%s.ico', [ResName]))); + + { load group icon resource } + R := FindResource(hModule, lpszName, lpszType); + if R = 0 then Exit; + Res := LoadResource(hModule, R); + if Res = 0 then Exit; + lpGroupIconDir := LockResource(Res); + if lpGroupIconDir = 0 then Exit; + RtlMoveMemoryWORD(idCount, lpGroupIconDir + 4{offset idCount}, SizeOf(idCount)); + if idCount = 0 then Exit; + + if bUpdate then + begin + { update resource helper } + n := GetArrayLength(ResHelper.Items); + SetArrayLength(ResHelper.Items, n + 1); + if lpszName shr $10 > 0 then + ResHelper.Items[n].szName := CastIntegerToString(lpszName) + else + ResHelper.Items[n].szName := Format('%d', [lpszName]); + EnumResourceLanguages(hModule, lpszType, lpszName, CallBackAddr('EnumResLangProc'), n); + + { delete 'RT_GROUP_ICON' } + if not UpdateResource(lParam, lpszType, lpszName, ResHelper.Items[n].wLanguage, 0, 0) then Exit; + + { delete the RT_ICON icon resources that belonged to 'RT_GROUP_ICON' } + for i := 0 to idCount - 1 do + begin + RtlMoveMemoryGRPIDE(grpide, lpGroupIconDir + 6{offset idEntries} + i * SizeOf(grpide), SizeOf(grpide)); + if not UpdateResource(lParam, RT_ICON, grpide.nID, ResHelper.Items[n].wLanguage, 0, 0) then Exit; + end; + + { open icon resource } + hFile := CreateFile(ExpandConstant(Format('{tmp}\resources\%s.ico', [ResName])), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if hFile = INVALID_HANDLE_VALUE then Exit; + try + hMapObject := CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, ''); + if hMapObject = 0 then Exit; + ResHelper.Items[n].lpIconDir := MapViewOfFile(hMapObject, FILE_MAP_READ, 0, 0, 0); + if ResHelper.Items[n].lpIconDir = 0 then Exit; + finally + CloseHandle(hMapObject); + CloseHandle(hFile); + end; + end + else + begin + { add nonupdatable icon ordinals } + for i := 0 to idCount - 1 do + begin + RtlMoveMemoryGRPIDE(grpide, lpGroupIconDir + 6{offset idEntries} + i * SizeOf(grpide), SizeOf(grpide)); + ResHelper.IconList.Add(Padz(IntToStr(grpide.nID), 5)); + end; + end; +end; + +////////////////////////////////////////////////////////////// +function UpdateFileResources(const FileName: string): Boolean; +var + H, M: THandle; + i, j: Integer; + idCount: WORD; + lpGrpData: GRPICONDIR; + cbGrpData: DWORD; + grpide: GRPICONDIRENTRY; + ide: ICONDIRENTRY; + bih: BITMAPINFOHEADER; +begin + M := LoadLibraryEx(FileName, 0, LOAD_LIBRARY_AS_DATAFILE); + if M = 0 then Exit; + H := BeginUpdateResource(FileName, False); + if H = 0 then Exit; + try + { enum resources } + EnumResourceNames(M, RT_GROUP_ICON, CallbackAddr('EnumResNameProc'), H); + + { update the resources } + for i := 0 to GetArrayLength(ResHelper.Items) - 1 do + begin + { check IconDir } + Result := (ResHelper.Items[i].lpIconDir <> 0); + if not Result then Exit; + + { build the new group icon resource } + RtlMoveMemoryWORD(idCount, ResHelper.Items[i].lpIconDir + 4{offset idCount}, SizeOf(idCount)); + cbGrpData := 6{offset idEntries} + idCount * SizeOf(grpide); + lpGrpData.idReserved := 0; + lpGrpData.idType := 1; + lpGrpData.idCount := idCount; + for j := 0 to idCount - 1 do + begin + RtlMoveMemoryIDE(ide, ResHelper.Items[i].lpIconDir + 6{offset idEntries} + j * SizeOf(ide), SizeOf(ide)); + RtlMoveMemoryBI(bih, ResHelper.Items[i].lpIconDir + ide.dwImageOffset, SizeOf(bih)); + lpGrpData.idEntries[j].bWidth := ide.bWidth; + lpGrpData.idEntries[j].bHeight := ide.bHeight; + if (bih.biClrUsed = 0) and (bih.biBitCount < 9) then + lpGrpData.idEntries[j].bColorCount := 1 shl bih.biBitCount + else + lpGrpData.idEntries[j].bColorCount := bih.biClrUsed; + lpGrpData.idEntries[j].bReserved := ide.bReserved; + lpGrpData.idEntries[j].wPlanes := bih.biPlanes; + lpGrpData.idEntries[j].wBitCount := bih.biBitCount; + lpGrpData.idEntries[j].dwBytesInRes := ide.dwBytesInRes; + lpGrpData.idEntries[j].nID := GetFreeIconIndex; + + { update 'MAINICON' } + with ResHelper.Items[i] do + if not UpdateResource(H, RT_ICON, lpGrpData.idEntries[j].nID, wLanguage, lpIconDir + ide.dwImageOffset, ide.dwBytesInRes) then Continue; + end; + + { update group } + with ResHelper.Items[i] do + if not UpdateResourcePtr(H, RT_GROUP_ICON, StrToIntDef(szName, CastStringToInteger(szName)), wLanguage, lpGrpData, cbGrpData) then Continue; + + { free memory } + UnmapViewOfFile(ResHelper.Items[i].lpIconDir); + end; + finally + FreeLibrary(M); + if Result then + Result := EndUpdateResource(H, not Result); + SetArrayLength(ResHelper.Items, 0); + ResHelper.IconList.Clear; + end; +end; + +////////////////////////////// +procedure UpdateResourcesProc; +var + RootPath, RootDir, DirName, FileName, OutputDir, AddParam: AnsiString; + ItemText: AnsiString; + i, ResultCode: Integer; +begin + { ResHelper } + Log(CustomMessage('cmLogUpdateResources1a')); + ResHelper.IconList := TStringList.Create; + ResHelper.IconList.Sorted := True; + ResHelper.IconList.Duplicates := dupIgnore; + + { update UI } + UpdateForm.Enabled := False; + ProgressBar.Max := 0; + SelectResTreeView.Selected := SelectResTreeView.TopItem; + for i := 0 to SelectResTreeView.Items.Count - 1 do + if (SelectResTreeView.Items[i].Level = 1) and (SelectResTreeView.Items[i].StateIndex = 2) then + ProgressBar.Max := ProgressBar.Max + 1; + + { prepare } + RootPath := ExtractFileDir(BrowseEdit.Text); + OutputDir := ExpandConstant('{tmp}\resources'); + for i := 0 to SelectResTreeView.Items.Count - 1 do + begin + ItemText := SelectResTreeView.Items[i].Text; + SelectResTreeView.Items[i].Selected := True; + if (SelectResTreeView.Items[i].StateIndex = 1) and (SelectResTreeView.Items[i].Level = 1) then + SelectResTreeView.Items[i].StateIndex := 4 + else if SelectResTreeView.Items[i].StateIndex = 2 then + begin + if SelectResTreeView.Items[i].Level = 0 then + RootDir := ItemText + else if SelectResTreeView.Items[i].Level = 1 then + begin + { update UI } + ProgressBar.Position := ProgressBar.Position + 1; + + { extract files } + FileName := ResourcesList[SelectArchiveComboBox.ItemIndex]; + AddParam := Format('%s\%s\*.ico', [RootDir, ItemText]); + Log(FmtMessage(CustomMessage('cmLogExtractResource7ZipFile'), [ExtractFileName(ItemText), ExtractFileName(FileName)])); + ResultCode := ExtractArchive(FileName, OutputDir, AddParam); + Log(FmtMessage(CustomMessage('cmLogResultCode'), [IntToStr(ResultCode)])); + if ResultCode = 0 then + begin + { get file } + case Lowercase(RootDir) of + 'root': + DirName := RootPath; + else + DirName := Format('%s\%s', [RootPath, RootDir]); + end; + FileName := FileSearch(ItemText + '.exe', DirName); + if FileName = '' then + FileName := FileSearch(ItemText + '.dll', DirName); + if FileName = '' then + FileName := FileSearch(ItemText + '.mir', DirName); + + { update UI } + StatusBar.Panels[0].Text := FmtMessage(CustomMessage('cmStatusLabelCaption1a'), [ExtractFileName(FileName)]); + StatusBar.Refresh; + + { update resources in file } + if FileExists(FileName) then + begin + if UpdateFileResources(FileName) then + begin + SelectResTreeView.Items[i].StateIndex := 3; // ok + Log(FmtMessage(CustomMessage('cmLogUpdateFileResourcesStatus1a'), [ExtractFileName(FileName)])); + end + else + begin + SelectResTreeView.Items[i].StateIndex := 5; // error + Log(FmtMessage(CustomMessage('cmLogUpdateFileResourcesStatus1b'), [ExtractFileName(FileName)])); + end; + end + else + begin + SelectResTreeView.Items[i].StateIndex := 4; // skip + Log(FmtMessage(CustomMessage('cmLogUpdateFileResourcesStatus1c'), [Format('%0:s.exe, %0:s.dll, %0:s.mir', [ItemText])])); + end; + + { cleanup } + DelTree(OutputDir + '\*.ico', False, True, False); + end; + end; + end; + end; + + { update UI } + SelectResButton.Caption := CustomMessage('cmSelectResButtonCaption1c'); + PatchButton.Enabled := False; + StatusBar.Panels[0].Text := CustomMessage('cmStatusLabelCaption1b'); + ProgressBar.Position := 0; + UpdateForm.Enabled := True; + + { cleanup } + ResHelper.IconList.Free; + Log(CustomMessage('cmLogUpdateResources1b')); +end; + +///////////////////////////////////////// +procedure ButtonOnClick(Sender: TObject); +var + i: Integer; + FileName: string; +begin + with TNewButton(Sender as TNewButton) do + case Sender of + SelectResButton: + begin + case Caption of + CustomMessage('cmSelectResButtonCaption1a'): + begin + Caption := CustomMessage('cmSelectResButtonCaption1b'); + for i := 0 to SelectResTreeView.Items.Count - 1 do + SelectResTreeView.Items[i].StateIndex := 2; + end; + CustomMessage('cmSelectResButtonCaption1b'): + begin + Caption := CustomMessage('cmSelectResButtonCaption1a'); + for i := 0 to SelectResTreeView.Items.Count - 1 do + SelectResTreeView.Items[i].StateIndex := 1; + end; + CustomMessage('cmSelectResButtonCaption1c'): + begin + PatchButton.Enabled := FileExists(BrowseEdit.Text) and (ResourcesList.Count > 0); + Caption := CustomMessage('cmSelectResButtonCaption1b'); + for i := 0 to SelectResTreeView.Items.Count - 1 do + SelectResTreeView.Items[i].StateIndex := 2; + end; + end; + end; + BrowseButton: + if GetOpenFileName(CustomMessage('cmBinariesPath'), FileName, '', CustomMessage('cmFilter'), 'Miranda??.exe') then + begin + BrowseEdit.Text := FileName; + PatchButton.Enabled := FileExists(BrowseEdit.Text) and (ResourcesList.Count > 0); + case SelectResButton.Caption of + CustomMessage('cmSelectResButtonCaption1c'): + begin + SelectResButton.Caption := CustomMessage('cmSelectResButtonCaption1b'); + for i := 0 to SelectResTreeView.Items.Count - 1 do + SelectResTreeView.Items[i].StateIndex := 2; + end; + end; + end; + PatchButton: + begin + Log(FmtMessage(CustomMessage('cmLogSelectedBinaryFile'), [BrowseEdit.Text])); + Log(FmtMessage(CustomMessage('cmLogSelectedResource7ZipFile'), [SelectArchiveComboBox.Text])); + UpdateResourcesProc; + end; + end; +end; + +////////////////////////////////////////////// +procedure BrowseEditOnChange(Sender: TObject); +begin + with TEdit(Sender as TEdit) do + begin + if FileExists(Text) then + Font.Color := clDefault + else + Font.Color := clRed; + end; + PatchButton.Enabled := FileExists(BrowseEdit.Text) and (ResourcesList.Count > 0); +end; + +///////////////////////////////////////////////////////// +procedure SelectArchiveComboBoxOnChange(Sender: TObject); +var + FileList, TempList: TStringList; + FileName, DirName, PrevFileName, PrevDirName: string; + i, Index: Integer; + bCheck: Boolean; +begin + with SelectResTreeView do + begin + if SelectArchiveComboBox.ItemIndex = -1 then Exit; + Items.Clear; + TempList := TStringList.Create; + TempList.Sorted := True; + TempList.CommaText := Lowercase(ExpandConstant('{param:RES|*}')); + FileList := TStringList(ResourcesList.Objects[SelectArchiveComboBox.ItemIndex] as TStringList); + for i := 0 to FileList.Count - 1 do + begin + DirName := ExtractFileDir(ExtractFileDir(FileList[i])); + FileName := ExtractFileName(ExtractFileDir(FileList[i])); + if DirName <> '' then + begin + if DirName <> PrevDirName then + begin + PrevDirName := DirName; + bCheck := (Trim(TempList.Text) = '*') or TempList.Find(Lowercase(DirName), Index); + Items.Add(Selected, DirName).Selected := True; + if bCheck then + Selected.StateIndex := 2 + else + Selected.StateIndex := 1; + end; + if FileName <> PrevFileName then + begin + PrevFileName := FileName; + Items.AddChild(Selected, FileName).StateIndex := Selected.StateIndex; + end; + end; + end; + Selected := Items[0]; + TempList.Free; + + { update UI } + PatchButton.Enabled := FileExists(BrowseEdit.Text) and (ResourcesList.Count > 0); + case SelectResButton.Caption of + CustomMessage('cmSelectResButtonCaption1c'): + begin + SelectResButton.Caption := CustomMessage('cmSelectResButtonCaption1b'); + for i := 0 to Items.Count - 1 do + Items[i].StateIndex := 2; + end; + end; + end; +end; + +////////////////////////////////////////////////////////////////////////////////////////////// +procedure StatusBarOnDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); +begin + ProgressBar.SetBounds(Rect.Left, Rect.Top, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top); + StatusBar.OnDrawPanel := nil; +end; + +////////////////////////////////////////////////////////////////////// +procedure TreeViewOnGetImageIndex(Sender: TObject; Node: TTreeNode); +begin + with Node do + begin + if Level = 0 then + begin + if HasChildren and Expanded then + ImageIndex := 1 + else + ImageIndex := 0; + end + else if Level = 1 then + ImageIndex := 2; + end; +end; + +/////////////////////////////////////////////////////////////////////// +procedure TreeViewOnGetSelectedIndex(Sender: TObject; Node: TTreeNode); +begin + with Node do + begin + if Level = 0 then + begin + if HasChildren and Expanded then + SelectedIndex := 1 + else + SelectedIndex := 0; + end + else if Level = 1 then + SelectedIndex := 2; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TreeViewOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +var + TreeView: TTreeView; + CurNode, FindNode, ParentNode: TTreeNode; +begin + if Button <> mbLeft then Exit; + TreeView := TTreeView(Sender as TTreeView); + CurNode := TreeView.GetNodeAt(X, Y); + if htOnStateIcon in TreeView.GetHitTestInfoAt(X, Y) then + with CurNode do + begin + if StateIndex = 2 then + StateIndex := 1 + else + StateIndex := 2; + if (Level = 0) and HasChildren then + begin + FindNode := GetFirstChild; + while Assigned(FindNode) do + begin + FindNode.StateIndex := StateIndex; + FindNode := GetNextChild(FindNode); + end; + end + else if (Level = 1) then + begin + FindNode := CurNode; + while Assigned(FindNode.GetPrevSibling) do + FindNode := FindNode.GetPrevSibling; + if StateIndex = 1 then + begin + ParentNode := FindNode.GetPrev; + while Assigned(FindNode) do + begin + if FindNode.StateIndex = 2 then Exit; + FindNode := GetNextChild(FindNode); + end; + ParentNode.StateIndex := StateIndex; + end + else + FindNode.GetPrev.StateIndex := 2; + end; + end; +end; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +procedure AddIconToImageList(const himl: HIMAGELIST; const hIcon: HICON; const bFreeIcon: Boolean); +var + bi: BITMAPINFO; + lpvBits: Longint; + cx, cy: Integer; +begin + with TBitmap.Create do + try + if not ImageList_GetIconSize(himl, cx, cy) then Exit; + Width := ScaleX(cx); + Height := ScaleY(cy); + bi.bmiHeader.biSize := SizeOf(bi.bmiHeader); + bi.bmiHeader.biWidth := Width; + bi.bmiHeader.biHeight := Height; + bi.bmiHeader.biPlanes := 1; + bi.bmiHeader.biBitCount := 32; + bi.bmiHeader.biCompression := BI_RGB; + bi.bmiHeader.biSizeImage := Width * Height * 4; + SetArrayLength(bi.bmiColors, Width * Height); + Handle := CreateDIBSection(Canvas.Handle, bi, DIB_RGB_COLORS, lpvBits, 0, 0); + DrawIconEx(Canvas.Handle, Width - Height, 0, hIcon, Height, Height, 0, 0, DI_NORMAL); + ImageList_Add(himl, Handle, 0); + finally + Free; + if bFreeIcon then + DestroyIcon(hIcon); + end; +end; + +procedure UpdateFormOnActivate(Sender: TObject); +begin + ShowWindow(Application.Handle, SW_HIDE); + SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle, GWL_EXSTYLE) or $80) ; + ShowWindow(Application.Handle, SW_SHOW); +end; + +/////////////////////////// +procedure CreateUpdateForm; +var + MainPanel, BrowsePanel, ButtonPanel: TPanel; + i: Integer; + shfi: SHFILEINFO; + hStateImgList: THandle; + hIcon: HICON; +begin + Application.Title := '{#AppName} {#AppVerName}'; + + { UpdateForm } + UpdateForm := TForm.Create(Application); + with UpdateForm do + begin + Width := ScaleX(370); + Height := ScaleY(400); + BorderStyle := bsSingle; + Caption := '{#AppName} {#AppVerName}'; + Position := poDesktopCenter; + end; + + { StatusBar } + StatusBar := TStatusBar.Create(UpdateForm); + with StatusBar do + begin + Parent := UpdateForm; + Align := alBottom; + ThemeBackground := False; + Panels.Add; + Panels[0].Width := 2 * UpdateForm.ClientWidth div 3; + Panels[0].Bevel := pbNone; + Panels.Add; + Panels[1].Style := psOwnerDraw; + Panels[1].Bevel := pbNone; + OnDrawPanel := @StatusBarOnDrawPanel; + end; + + { ProgressBar } + ProgressBar := TNewProgressBar.Create(UpdateForm); + with ProgressBar do + begin + Parent := StatusBar; + end; + + { MainPanel } + MainPanel := TPanel.Create(UpdateForm); + with MainPanel do + begin + Parent := UpdateForm; + Align := alClient; + BevelOuter := bvNone; + end; + + { Bevel } + with TBevel.Create(UpdateForm) do + begin + Parent := UpdateForm; + Align := alBottom; + Shape := bsTopLine; + Style := bsLowered; + Height := 1; + end; + + { BinariesPath } + with TStatusBar.Create(UpdateForm) do + begin + Parent := MainPanel; + Height := ScaleY(21); + Align := alTop; + ThemeBackground := False; + Panels.Add; + Panels[0].Bevel := pbNone; + Panels[0].Text := CustomMessage('cmBinariesPath'); + end; + + { BrowsePanel } + BrowsePanel := TPanel.Create(UpdateForm); + with BrowsePanel do + begin + Parent := MainPanel; + Top := Parent.ClientHeight; + Align := alTop; + BevelOuter := bvNone; + end; + + { BrowseButton } + BrowseButton := TNewButton.Create(UpdateForm); + with BrowseButton do + begin + Parent := BrowsePanel; + Align := alRight; + Height := ScaleY(21); + Width := Height; + BrowsePanel.Height := Height; + Caption := '...'; + OnClick := @ButtonOnClick; + end; + + { BrowseEdit } + BrowseEdit := TEdit.Create(UpdateForm); + with BrowseEdit do + begin + Parent := BrowsePanel; + Top := (BrowseButton.Height - Height) div 2; + Width := Parent.ClientWidth - Parent.ClientHeight; + ReadOnly := True; + if FileExists(ExpandConstant('{param:BIN}')) then + Text := ExpandConstant('{param:BIN}'); + OnChange := @BrowseEditOnChange; + end; + + { SelectArchive } + with TStatusBar.Create(UpdateForm) do + begin + Parent := MainPanel; + Top := Parent.ClientHeight; + Height := ScaleY(24); + Align := alTop; + ThemeBackground := False; + Panels.Add; + Panels[0].Bevel := pbNone; + Panels[0].Text := CustomMessage('cmSelectArchive'); + end; + + { SelectArchiveComboBox } + SelectArchiveComboBox := TComboBox.Create(UpdateForm); + with SelectArchiveComboBox do + begin + Parent := MainPanel; + Top := Parent.ClientHeight; + Align := alTop; + Style := csDropDownList; + for i := 0 to ResourcesList.Count - 1 do + Items.Add(ExtractFileName(ResourcesList[i])); + ResourcesList.Find(ExpandFileName(ExpandConstant('{param:ARC}.7z')), i); + ItemIndex := i; + OnChange := @SelectArchiveComboBoxOnChange; + end; + + { SelectResources } + with TStatusBar.Create(UpdateForm) do + begin + Parent := MainPanel; + Top := Parent.ClientHeight; + Height := ScaleY(24); + Align := alTop; + ThemeBackground := False; + Panels.Add; + Panels[0].Bevel := pbNone; + Panels[0].Text := CustomMessage('cmSelectResources'); + end; + + { ButtonPanel } + ButtonPanel := TPanel.Create(UpdateForm); + with ButtonPanel do + begin + Parent := MainPanel; + Align := alBottom; + BevelOuter := bvNone; + end; + + { SelectResButton } + SelectResButton := TNewButton.Create(UpdateForm); + with SelectResButton do + begin + Parent := ButtonPanel; + Align := alLeft; + ButtonPanel.Height := Height; + Caption := CustomMessage('cmSelectResButtonCaption1b'); + OnClick := @ButtonOnClick; + end; + + { PatchButton } + PatchButton := TNewButton.Create(UpdateForm); + with PatchButton do + begin + Parent := ButtonPanel; + Align := alRight; + Caption := CustomMessage('cmPatchButtonCaption'); + OnClick := @ButtonOnClick; + end; + + { SelectResTreeView } + SelectResTreeView := TTreeView.Create(UpdateForm); + with SelectResTreeView do + begin + Parent := MainPanel; + Align := alClient; + ReadOnly := True; + HideSelection := False; + SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) or TVS_CHECKBOXES); + SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_COMPOSITED); + + { create imagelist } + Images := TImageList.Create(UpdateForm); + Images.Handle := ImageList_Create(ScaleX(18), ScaleY(16), ILC_COLOR32, 0, 0); + if SHGetFileInfo(ExpandConstant('{tmp}'), 0, shfi, SizeOf(shfi), SHGFI_ICON or SHGFI_SMALLICON) <> 0 then + AddIconToImageList(Images.Handle, shfi.hIcon, False); + if SHGetFileInfo(ExpandConstant('{tmp}'), 0, shfi, SizeOf(shfi), SHGFI_ICON or SHGFI_SMALLICON or SHGFI_OPENICON) <> 0 then + AddIconToImageList(Images.Handle, shfi.hIcon, False); + hIcon := LoadImage(HInstance, '_IS_PLUGIN', IMAGE_ICON, 0, 0, 0); + if hIcon <> 0 then + AddIconToImageList(Images.Handle, hIcon, True); + + { state imagelist } + hStateImgList := SendMessage(Handle, TVM_GETIMAGELIST, TVSIL_STATE, 0); + if hStateImgList <> 0 then + begin + hIcon := LoadImage(HInstance, '_IS_DONE', IMAGE_ICON, 0, 0, 0); + if hIcon <> 0 then + AddIconToImageList(hStateImgList, hIcon, False); + hIcon := LoadImage(HInstance, '_IS_SKIP', IMAGE_ICON, 0, 0, 0); + if hIcon <> 0 then + AddIconToImageList(hStateImgList, hIcon, False); + hIcon := LoadImage(HInstance, '_IS_ERROR', IMAGE_ICON, 0, 0, 0); + if hIcon <> 0 then + AddIconToImageList(hStateImgList, hIcon, False); + StateImages := TImageList.Create(UpdateForm); + StateImages.Handle := hStateImgList; + end; + + OnGetImageIndex := @TreeViewOnGetImageIndex; + OnGetSelectedIndex := @TreeViewOnGetSelectedIndex; + OnMouseDown := @TreeViewOnMouseDown; + SelectArchiveComboBoxOnChange(SelectArchiveComboBox); + end; + + { do work } + try + if IsParameter('/SILENT') then + begin + MainPanel.Hide; + UpdateForm.ClientHeight := StatusBar.Height; + UpdateForm.Show; + if PatchButton.Enabled then + PatchButton.Click; + Exit; + end + else if IsParameter('/VERYSILENT') then + begin + ShowWindow(Application.Handle, SW_HIDE); + if PatchButton.Enabled then + PatchButton.Click; + Exit; + end + else + UpdateForm.ShowModal; + finally + { cleanup } + for i := 0 to ResourcesList.Count - 1 do + TStringList(ResourcesList.Objects[i] as TStringList).Free; + ResourcesList.Free; + UpdateForm.Free; + end; +end; + +////////////////////////////////// +function InitializeSetup: Boolean; +begin + Result := False; + if not DisplayHelp then + if CheckSource then + CreateUpdateForm; +end; diff --git a/tools/IconPatcher/{res}/7-zip32.dll b/tools/IconPatcher/{res}/7-zip32.dll new file mode 100644 index 0000000000..91c810183d Binary files /dev/null and b/tools/IconPatcher/{res}/7-zip32.dll differ diff --git a/tools/IconPatcher/{res}/done.ico b/tools/IconPatcher/{res}/done.ico new file mode 100644 index 0000000000..bc78f7df8f Binary files /dev/null and b/tools/IconPatcher/{res}/done.ico differ diff --git a/tools/IconPatcher/{res}/error.ico b/tools/IconPatcher/{res}/error.ico new file mode 100644 index 0000000000..af5a099e3f Binary files /dev/null and b/tools/IconPatcher/{res}/error.ico differ diff --git a/tools/IconPatcher/{res}/icon.ico b/tools/IconPatcher/{res}/icon.ico new file mode 100644 index 0000000000..6179512f8d Binary files /dev/null and b/tools/IconPatcher/{res}/icon.ico differ diff --git a/tools/IconPatcher/{res}/iconpatcher_en.isl b/tools/IconPatcher/{res}/iconpatcher_en.isl new file mode 100644 index 0000000000..6a0585dba0 --- /dev/null +++ b/tools/IconPatcher/{res}/iconpatcher_en.isl @@ -0,0 +1,37 @@ +[LangOptions] +LanguageName=English +LanguageID=$0409 +LanguageCodePage=0 + +[CustomMessages] +; *** "UpdateForm form" +cmFileNotFound=Archives not found. +cmBinariesPath=Enter path to executable file Miranda32/64.exe: +cmFilter=Miranda??.exe file (Miranda??.exe)|Miranda??.exe +cmSelectArchive=Select an archive from the list: +cmSelectResources=Select resources: +cmSelectResButtonCaption1a=Select all +cmSelectResButtonCaption1b=Nothing +cmSelectResButtonCaption1c=Reset +cmPatchButtonCaption=Patch +cmStatusLabelCaption1a=Processing: %1 +cmStatusLabelCaption1b=Ready + +; *** "Logs" +cmLogFindResource7ZipFile1a=Resource archive search started +cmLogFindResource7ZipFile1b=Resource archive search finished +cmLogResource7ZipFile=Archive found: %1 +cmLogResource7ZipFileContent=List of archive files: %1 +cmLogSelectedBinaryFile=Executable file selected: %1 +cmLogSelectedResource7ZipFile=Resource file selected: %1 +cmLogUpdateResources1a=Resource patching started +cmLogUpdateResources1b=Resource patching finished +cmLogExtractResource7ZipFile=Resource unpacking for %1.* is %2 +cmLogUpdateFileResourcesStatus1a=Resource replacement for file %1: succeeded +cmLogUpdateFileResourcesStatus1b=Resource replacement for file %1: failed +cmLogUpdateFileResourcesStatus1c=Resource updating: skipped. None of %1 files found +cmLogResultCode=Return code: %1 + +; *** "Help Message" +cmHelpMsgCaption=Command-line syntax %1 +cmHelpMsg=Usage:%n %1 [ /? | /bin="exepath" | /arc="arcname" | /res=reslist|* ]%n%nWhere%n /? - displays this help message%n exepath - path to Miranda32/64.exe%n arcname - 7z-archive filename with resources without extension%n reslist - resource list (or list of root folders), comma separated \ No newline at end of file diff --git a/tools/IconPatcher/{res}/iconpatcher_ru.isl b/tools/IconPatcher/{res}/iconpatcher_ru.isl new file mode 100644 index 0000000000..352c7624b4 --- /dev/null +++ b/tools/IconPatcher/{res}/iconpatcher_ru.isl @@ -0,0 +1,37 @@ +[LangOptions] +LanguageName=<0420><0443><0441><0441><043A><0438><0439> +LanguageID=$0419 +LanguageCodePage=1251 + +[CustomMessages] +; *** "UpdateForm form" +cmFileNotFound=Архивы не найдены. +cmBinariesPath=Укажите путь к исполняемому файлу Miranda32/64.exe: +cmFilter=Файл Miranda??.exe (Miranda??.exe)|Miranda??.exe +cmSelectArchive=Выберите архив из списка: +cmSelectResources=Выберите ресурсы: +cmSelectResButtonCaption1a=Выбрать все +cmSelectResButtonCaption1b=Снять все +cmSelectResButtonCaption1c=Сбросить +cmPatchButtonCaption=Патчить +cmStatusLabelCaption1a=Обработка: %1 +cmStatusLabelCaption1b=Готово + +; *** "Logs" +cmLogFindResource7ZipFile1a=Поиск архивов с ресурсами начат +cmLogFindResource7ZipFile1b=Поиск архивов с ресурсами завершен +cmLogResource7ZipFile=Найден архив: %1 +cmLogResource7ZipFileContent=Список файлов архива: %1 +cmLogSelectedBinaryFile=Выбран исполняемый файл: %1 +cmLogSelectedResource7ZipFile=Выбран файл с ресурсами: %1 +cmLogUpdateResources1a=Обновление ресурсов начато +cmLogUpdateResources1b=Обновление ресурсов завершено +cmLogExtractResource7ZipFile=Распаковка ресурсов для файла %1.* из %2 +cmLogUpdateFileResourcesStatus1a=Обновление ресурсов в файле %1: успех +cmLogUpdateFileResourcesStatus1b=Обновление ресурсов в файле %1: ошибка +cmLogUpdateFileResourcesStatus1c=Обновление ресурсов: пропуск. Ни один из файлов %1 не найден +cmLogResultCode=Код возврата: %1 + +; *** "Help Message" +cmHelpMsgCaption=Синтаксис командной строки %1 +cmHelpMsg=Использование:%n %1 [ /? | /bin="exepath" | /arc="arcname" | /res=reslist|* ]%n%nГде%n /? - Отобразить это справочное сообщение%n exepath - Путь к файлу Miranda32/64.exe%n arcname - Имя 7z-архива c ресурсами без расширения%n reslist - Список ресурсов (корневых папок), разделенных через запятую \ No newline at end of file diff --git a/tools/IconPatcher/{res}/plugin.ico b/tools/IconPatcher/{res}/plugin.ico new file mode 100644 index 0000000000..c098ce4db6 Binary files /dev/null and b/tools/IconPatcher/{res}/plugin.ico differ diff --git a/tools/IconPatcher/{res}/skip.ico b/tools/IconPatcher/{res}/skip.ico new file mode 100644 index 0000000000..288ee06e53 Binary files /dev/null and b/tools/IconPatcher/{res}/skip.ico differ -- cgit v1.2.3