mirror of
https://github.com/electron/rcedit
synced 2026-08-09 12:35:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e95698dd8d | ||
|
|
acadee1941 | ||
|
|
004ab2ecfb | ||
|
|
3ff5efbf3c | ||
|
|
7363128fbb | ||
|
|
4e82e9ea79 | ||
|
|
ea2555f04d | ||
|
|
a13150faeb | ||
|
|
612613d83f | ||
|
|
086de8cfa0 | ||
|
|
4d0d543ff6 | ||
|
|
40667ffeae | ||
|
|
47e05b3169 | ||
|
|
20b8b04597 | ||
|
|
89caddde11 | ||
|
|
73e7570923 | ||
|
|
1d1bb83160 | ||
|
|
a3e0521025 | ||
|
|
eabbeb5ae1 | ||
|
|
145b0785ab | ||
|
|
554d492b78 | ||
|
|
343381add4 | ||
|
|
0bfeb33867 | ||
|
|
205dce4755 | ||
|
|
e36b688b42 | ||
|
|
2d04a82a41 | ||
|
|
88957b5269 | ||
|
|
14d46c540c | ||
|
|
cb3a368eaf | ||
|
|
5ffdf5b197 | ||
|
|
e44f48cfca | ||
|
|
6af08cd835 | ||
|
|
9843285649 | ||
|
|
08227ad68f | ||
|
|
ccea00e588 | ||
|
|
05fef00312 | ||
|
|
acd3d9b4e2 | ||
|
|
4fea46803d | ||
|
|
908a942dbc | ||
|
|
d14a049f24 | ||
|
|
c6bfd11070 | ||
|
|
5e90f6efb8 | ||
|
|
b010e00f92 | ||
|
|
befe2c1d0f | ||
|
|
28a1319059 | ||
|
|
4ea6c4cc58 | ||
|
|
a7531acc7a | ||
|
|
0c4394103a | ||
|
|
b1f8a3babe | ||
|
|
824746d522 | ||
|
|
228fcd00f8 | ||
|
|
9b04a43f6d | ||
|
|
b807b34a64 | ||
|
|
3a8e8239da | ||
|
|
2034ced86e | ||
|
|
9243fe7b1b | ||
|
|
ca7064eb01 | ||
|
|
6daf749a38 | ||
|
|
741942e011 | ||
|
|
19f6af7a61 |
@@ -1,43 +0,0 @@
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
|
||||
configuration: Default
|
||||
|
||||
platform:
|
||||
- x64
|
||||
- Win32
|
||||
|
||||
before_build:
|
||||
- cmd: |
|
||||
git clone --depth 1 https://chromium.googlesource.com/external/gyp
|
||||
gyp\gyp rcedit.gyp --depth .
|
||||
|
||||
build:
|
||||
project: rcedit.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
|
||||
after_build:
|
||||
- cmd: if %PLATFORM%==Win32 (move Default\rcedit.exe Default\rcedit-x86.exe)
|
||||
- cmd: if %PLATFORM%==x64 (move Default\rcedit.exe Default\rcedit-x64.exe)
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
artifacts:
|
||||
- path: Default\*.exe
|
||||
|
||||
deploy:
|
||||
- provider: GitHub
|
||||
release: Rcedit $(APPVEYOR_REPO_TAG_NAME)
|
||||
tag: $(APPVEYOR_REPO_TAG_NAME)
|
||||
description: '(placeholder)'
|
||||
auth_token:
|
||||
secure: lVaYho+MDDKAQH4aImQub/L5ORlENgZ4utufxWAetovWnIsWiwFCkgFRIcIRMWz5
|
||||
artifact: /.*\.exe/
|
||||
draft: true
|
||||
force_update: true
|
||||
prerelease: false
|
||||
on:
|
||||
appveyor_repo_tag: true
|
||||
@@ -0,0 +1 @@
|
||||
* @electron/wg-ecosystem
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Add to Ecosystem WG Project
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Generate GitHub App token
|
||||
uses: electron/github-app-auth-action@e14e47722ed120360649d0789e25b9baece12725 # v2.0.0
|
||||
id: generate-token
|
||||
with:
|
||||
creds: ${{ secrets.ECOSYSTEM_ISSUE_TRIAGE_GH_APP_CREDS }}
|
||||
org: electron
|
||||
- name: Add to Project
|
||||
uses: dsanders11/project-actions/add-item@5767984408ccc6742f83acc8b8d8ea5e09f329af # v2.0.0
|
||||
with:
|
||||
field: Opened
|
||||
field-value: ${{ github.event.pull_request.created_at || github.event.issue.created_at }}
|
||||
project-number: 89
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
@@ -0,0 +1,84 @@
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -E make_directory build/x64
|
||||
cmake -E make_directory build/Win32
|
||||
cd build/x64
|
||||
cmake -A x64 ../../
|
||||
cmake --build . --config RelWithDebInfo
|
||||
cd ../../build/Win32
|
||||
cmake -A Win32 ../../
|
||||
cmake --build . --config RelWithDebInfo
|
||||
- name: Copy to dist
|
||||
run: |
|
||||
cmake -E make_directory dist
|
||||
cmake -E copy build/x64/RelWithDebInfo/rcedit.exe dist/rcedit-x64.exe
|
||||
cmake -E copy build/Win32/RelWithDebInfo/rcedit.exe dist/rcedit-x86.exe
|
||||
- name: Print help
|
||||
shell: bash
|
||||
run: |
|
||||
set -eo pipefail
|
||||
dist/rcedit-x86.exe -h
|
||||
dist/rcedit-x64.exe -h
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: windows-2022
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/main'
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
id: checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
|
||||
with:
|
||||
name: dist
|
||||
path: dist/
|
||||
- run: npm install -g semantic-release@22.0.6 semantic-release-export-data@v1.0.1
|
||||
- run: npx semantic-release@22.0.6 --dry-run
|
||||
id: get-next-version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Stamp version
|
||||
if: steps.get-next-version.outputs.new-release-published == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -eo pipefail
|
||||
dist/rcedit-x64.exe dist/rcedit-x86.exe --set-product-version $VERSION --set-file-version $VERSION
|
||||
dist/rcedit-x86.exe -h | grep -q "Rcedit v$VERSION"
|
||||
dist/rcedit-x86.exe dist/rcedit-x64.exe --set-product-version $VERSION --set-file-version $VERSION
|
||||
dist/rcedit-x64.exe -h | grep -q "Rcedit v$VERSION"
|
||||
env:
|
||||
VERSION: ${{ steps.get-next-version.outputs.new-release-version }}
|
||||
- name: Run semantic release
|
||||
run: npx semantic-release@22.0.6
|
||||
if: steps.get-next-version.outputs.new-release-published == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,26 @@
|
||||
name: "Check Semantic Commit"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
main:
|
||||
permissions:
|
||||
pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs
|
||||
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
|
||||
name: Validate PR Title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: semantic-pull-request
|
||||
uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
validateSingleCommit: false
|
||||
@@ -1,5 +1,6 @@
|
||||
Default/
|
||||
ipch/
|
||||
build/
|
||||
|
||||
*.swp
|
||||
*.sdf
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"plugins": [
|
||||
"semantic-release-export-data",
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
[
|
||||
"@semantic-release/github",
|
||||
{
|
||||
"assets": [
|
||||
{ "path": "dist/rcedit-x64.exe" },
|
||||
{ "path": "dist/rcedit-x86.exe" }
|
||||
],
|
||||
"draftRelease": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"branches": [ "main" ]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
|
||||
|
||||
# /Ox, full optimization
|
||||
# /Os, favour small code
|
||||
add_compile_options(/Ox /Os)
|
||||
|
||||
project(rcedit)
|
||||
|
||||
add_executable(rcedit src/main.cc src/rescle.cc src/rcedit.rc)
|
||||
target_link_libraries(rcedit version.lib)
|
||||
@@ -1,24 +1,22 @@
|
||||
# rcedit [](https://ci.appveyor.com/project/zcbenz/rcedit/branch/master)
|
||||
# rcedit
|
||||
|
||||
[](https://github.com/electron/rcedit/actions/workflows/ci.yml)
|
||||
|
||||
Command line tool to edit resources of exe file on Windows.
|
||||
|
||||
## Executables
|
||||
|
||||
Prebuilt binaries can be found in the artifacts of appveyor jobs.
|
||||
Prebuilt binaries can be found in the [GitHub releases](https://github.com/electron/rcedit/releases).
|
||||
|
||||
## Building
|
||||
|
||||
To build you need CMake 3.15+ and Visual Studio 2015 or above.
|
||||
|
||||
1. Clone the repository
|
||||
2. Open `rcedit.sln` with Visual Studio 2015 or above
|
||||
3. Build
|
||||
|
||||
## Generate solution files
|
||||
|
||||
If you have modified the gyp files, you should regenerate the solution files:
|
||||
|
||||
1. Make sure you have gyp is configured in your system. If not, clone gyp from
|
||||
https://chromium.googlesource.com/external/gyp
|
||||
2. Run `gyp rcedit.gyp --depth .`
|
||||
2. Create a build directory: `cmake -E make_directory build`
|
||||
3. Change to the build directory: `cd build`
|
||||
4. Make the CMake project: `cmake ..`
|
||||
5. Build: `cmake --build . --config RelWithDebInfo`
|
||||
|
||||
## Docs
|
||||
|
||||
@@ -90,4 +88,4 @@ Get resource string:
|
||||
|
||||
```bash
|
||||
$ rcedit "path-to-exe-or-dll" --get-resource-string id_number
|
||||
```
|
||||
```
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'rcedit',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'src/main.cc',
|
||||
'src/rescle.cc',
|
||||
'src/rescle.h',
|
||||
'src/rcedit.rc',
|
||||
'src/version.h',
|
||||
],
|
||||
'msvs_settings': {
|
||||
'VCLinkerTool': {
|
||||
'SubSystem': 1, # console executable
|
||||
},
|
||||
'VCCLCompilerTool': {
|
||||
'Optimization': 3, # /Ox, full optimization
|
||||
'FavorSizeOrSpeed': 1, # /Os, favour small code
|
||||
'RuntimeLibrary': 0, # /MT, for statically linked runtime
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
['MSVS_VERSION=="2015"', {
|
||||
'msbuild_toolset': 'v140_xp',
|
||||
}],
|
||||
['MSVS_VERSION=="2017"', {
|
||||
'msbuild_toolset': 'v141_xp',
|
||||
}],
|
||||
],
|
||||
'configurations': {
|
||||
'Default': {
|
||||
},
|
||||
'Default_x64': {
|
||||
'msvs_configuration_platform': 'x64',
|
||||
},
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2015
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcedit", "rcedit.vcxproj", "{3609DBE4-DFE6-667B-C659-D6913E25C767}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Default|x64 = Default|x64
|
||||
Default|Win32 = Default|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3609DBE4-DFE6-667B-C659-D6913E25C767}.Default|x64.ActiveCfg = Default|x64
|
||||
{3609DBE4-DFE6-667B-C659-D6913E25C767}.Default|x64.Build.0 = Default|x64
|
||||
{3609DBE4-DFE6-667B-C659-D6913E25C767}.Default|Win32.ActiveCfg = Default|Win32
|
||||
{3609DBE4-DFE6-667B-C659-D6913E25C767}.Default|Win32.Build.0 = Default|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,82 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Default|Win32">
|
||||
<Configuration>Default</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Default|x64">
|
||||
<Configuration>Default</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{3609DBE4-DFE6-667B-C659-D6913E25C767}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>rcedit</RootNamespace>
|
||||
<IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/>
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Locals">
|
||||
<PlatformToolset>v140_xp</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/>
|
||||
<ImportGroup Label="ExtensionSettings"/>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/>
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros"/>
|
||||
<PropertyGroup>
|
||||
<ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\.\bin\;$(MSBuildProjectDirectory)\.\bin\</ExecutablePath>
|
||||
<IntDir>$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<TargetName>$(ProjectName)</TargetName>
|
||||
<TargetPath>$(OutDir)\$(ProjectName)$(TargetExt)</TargetPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Default|Win32'">
|
||||
<ClCompile>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<Optimization>Full</Optimization>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies></AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Default|x64'">
|
||||
<ClCompile>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<Optimization>Full</Optimization>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies></AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(ProjectName)$(TargetExt)</OutputFile>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="rcedit.gyp"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\rescle.h"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\main.cc"/>
|
||||
<ClCompile Include="src\rescle.cc"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="src\rcedit.rc"/>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/>
|
||||
<ImportGroup Label="ExtensionTargets"/>
|
||||
</Project>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{8CDEE807-BC53-E450-C8B8-4DEBB66742D4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\main.cc">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\rescle.cc">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="src\rescle.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ResourceCompile Include="src\rcedit.rc">
|
||||
<Filter>src</Filter>
|
||||
</ResourceCompile>
|
||||
<None Include="rcedit.gyp"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+61
-5
@@ -3,15 +3,47 @@
|
||||
// LICENSE file.
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include <windows.h>
|
||||
#include <winver.h>
|
||||
|
||||
#include "rescle.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void print_help() {
|
||||
std::vector<uint8_t> get_file_version_info() {
|
||||
DWORD zero = 0;
|
||||
std::vector<wchar_t> filename(MAX_PATH);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
|
||||
do {
|
||||
GetModuleFileNameW(NULL, filename.data(), filename.size());
|
||||
|
||||
// Double the buffer size in case the path is longer
|
||||
filename.resize(filename.size() * 2);
|
||||
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
|
||||
|
||||
if (GetLastError() != ERROR_SUCCESS) {
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
DWORD file_ver_info_size = GetFileVersionInfoSizeW(filename.data(), &zero);
|
||||
if (file_ver_info_size == 0) {
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> file_ver_info(file_ver_info_size);
|
||||
if (!GetFileVersionInfoW(filename.data(), NULL, file_ver_info.size(), file_ver_info.data())) {
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
return file_ver_info;
|
||||
}
|
||||
|
||||
void print_help(VS_FIXEDFILEINFO* file_info) {
|
||||
fprintf(stdout,
|
||||
"Rcedit " RCEDIT_VERSION ": Edit resources of exe.\n\n"
|
||||
"Rcedit v%d.%d.%d: Edit resources of exe.\n\n"
|
||||
"Usage: rcedit <filename> [options...]\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Show this message\n"
|
||||
@@ -23,7 +55,11 @@ void print_help() {
|
||||
" --set-requested-execution-level <level> Pass nothing to see usage\n"
|
||||
" --application-manifest <path-to-file> Set manifest file\n"
|
||||
" --set-resource-string <key> <value> Set resource string\n"
|
||||
" --get-resource-string <key> Get resource string\n");
|
||||
" --get-resource-string <key> Get resource string\n"
|
||||
" --set-rcdata <key> <path-to-file> Replace RCDATA by integer id\n",
|
||||
(file_info->dwProductVersionMS >> 16) & 0xff,
|
||||
(file_info->dwProductVersionMS >> 0) & 0xff,
|
||||
(file_info->dwProductVersionLS >> 16) & 0xff);
|
||||
}
|
||||
|
||||
bool print_error(const char* message) {
|
||||
@@ -53,7 +89,15 @@ int wmain(int argc, const wchar_t* argv[]) {
|
||||
if (argc == 1 ||
|
||||
(argc == 2 && wcscmp(argv[1], L"-h") == 0) ||
|
||||
(argc == 2 && wcscmp(argv[1], L"--help") == 0)) {
|
||||
print_help();
|
||||
UINT ignored = 0;
|
||||
VS_FIXEDFILEINFO* file_info = nullptr;
|
||||
std::vector<uint8_t> file_version_info = get_file_version_info();
|
||||
|
||||
if (file_version_info.size() == 0 || !VerQueryValueW(file_version_info.data(), L"\\", (LPVOID*) &file_info, &ignored)) {
|
||||
return print_error("Could not determine version of rcedit");
|
||||
}
|
||||
|
||||
print_help(file_info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -154,6 +198,18 @@ int wmain(int argc, const wchar_t* argv[]) {
|
||||
if (!updater.ChangeString(key_id, value))
|
||||
return print_error("Unable to change string");
|
||||
|
||||
} else if (wcscmp(argv[i], L"--set-rcdata") == 0) {
|
||||
if (argc - i < 3)
|
||||
return print_error("--set-rcdata requires int 'Key' and path to resource 'Value'");
|
||||
|
||||
const wchar_t* key = argv[++i];
|
||||
unsigned int key_id = 0;
|
||||
if (swscanf_s(key, L"%d", &key_id) != 1)
|
||||
return print_error("Unable to parse id");
|
||||
|
||||
const wchar_t* pathToResource = argv[++i];
|
||||
if (!updater.ChangeRcData(key_id, pathToResource))
|
||||
return print_error("Unable to change RCDATA");
|
||||
} else if (wcscmp(argv[i], L"--get-resource-string") == 0 ||
|
||||
wcscmp(argv[i], L"-grs") == 0) {
|
||||
if (argc - i < 2)
|
||||
|
||||
Binary file not shown.
+88
-8
@@ -13,6 +13,7 @@
|
||||
#include <iomanip> // setw, setfill
|
||||
#include <fstream>
|
||||
#include <codecvt>
|
||||
#include <algorithm>
|
||||
|
||||
namespace rescle {
|
||||
|
||||
@@ -75,6 +76,7 @@ typedef struct _VS_VERSION_ROOT {
|
||||
// The default en-us LANGID.
|
||||
LANGID kLangEnUs = 1033;
|
||||
LANGID kCodePageEnUs = 1200;
|
||||
UINT kDefaultIconBundle = 0;
|
||||
|
||||
template<typename T>
|
||||
inline T round(T value, int modula = 4) {
|
||||
@@ -417,6 +419,7 @@ bool ResourceUpdater::Load(const WCHAR* filename) {
|
||||
EnumResourceNamesW(module_, RT_GROUP_ICON, OnEnumResourceName, reinterpret_cast<LONG_PTR>(this));
|
||||
EnumResourceNamesW(module_, RT_ICON, OnEnumResourceName, reinterpret_cast<LONG_PTR>(this));
|
||||
EnumResourceNamesW(module_, RT_MANIFEST, OnEnumResourceManifest, reinterpret_cast<LONG_PTR>(this));
|
||||
EnumResourceNamesW(module_, RT_RCDATA, OnEnumResourceName, reinterpret_cast<LONG_PTR>(this));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -553,6 +556,43 @@ bool ResourceUpdater::ChangeString(UINT id, const WCHAR* value) {
|
||||
return ChangeString(langId, id, value);
|
||||
}
|
||||
|
||||
bool ResourceUpdater::ChangeRcData(UINT id, const WCHAR* pathToResource) {
|
||||
auto rcDataLngPairIt = std::find_if(rcDataLngMap_.begin(), rcDataLngMap_.end(), [=](const auto& rcDataLngPair) {
|
||||
return rcDataLngPair.second.find(id) != rcDataLngPair.second.end();
|
||||
});
|
||||
|
||||
if (rcDataLngPairIt == rcDataLngMap_.end()) {
|
||||
fprintf(stderr, "Cannot find RCDATA with id '%u'\n", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t abspath[MAX_PATH] = { 0 };
|
||||
const auto filePath = _wfullpath(abspath, pathToResource, MAX_PATH) ? abspath : pathToResource;
|
||||
ScopedFile newRcDataFile(filePath);
|
||||
if (newRcDataFile == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Cannot open new data file '%ws'\n", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto dwFileSize = GetFileSize(newRcDataFile, NULL);
|
||||
if (dwFileSize == INVALID_FILE_SIZE) {
|
||||
fprintf(stderr, "Cannot get file size for '%ws'\n", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& rcData = rcDataLngPairIt->second[id];
|
||||
rcData.clear();
|
||||
rcData.resize(dwFileSize);
|
||||
|
||||
DWORD dwBytesRead{ 0 };
|
||||
if (!ReadFile(newRcDataFile, rcData.data(), dwFileSize, &dwBytesRead, NULL)) {
|
||||
fprintf(stderr, "Cannot read file '%ws'\n", filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const WCHAR* ResourceUpdater::GetString(WORD languageId, UINT id) {
|
||||
StringTable& table = stringTableMap_[languageId];
|
||||
|
||||
@@ -587,24 +627,24 @@ bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId,
|
||||
|
||||
ScopedFile file(path);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Cannot open icon file '%s'\n", path);
|
||||
fwprintf(stderr, L"Cannot open icon file '%ls'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
IconsValue::ICONHEADER& header = icon.header;
|
||||
if (!ReadFile(file, &header, 3 * sizeof(WORD), &bytes, NULL)) {
|
||||
fprintf(stderr, "Cannot read icon header for '%s'\n", path);
|
||||
fwprintf(stderr, L"Cannot read icon header for '%ls'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.reserved != 0 || header.type != 1) {
|
||||
fprintf(stderr, "Reserved header is not 0 or image type is not icon for '%s'\n", path);
|
||||
fwprintf(stderr, L"Reserved header is not 0 or image type is not icon for '%ls'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
header.entries.resize(header.count);
|
||||
if (!ReadFile(file, header.entries.data(), header.count * sizeof(IconsValue::ICONENTRY), &bytes, NULL)) {
|
||||
fprintf(stderr, "Cannot read icon metadata for '%s'\n", path);
|
||||
fwprintf(stderr, L"Cannot read icon metadata for '%ls'\n", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -613,7 +653,7 @@ bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId,
|
||||
icon.images[i].resize(header.entries[i].bytesInRes);
|
||||
SetFilePointer(file, header.entries[i].imageOffset, NULL, FILE_BEGIN);
|
||||
if (!ReadFile(file, icon.images[i].data(), icon.images[i].size(), &bytes, NULL)) {
|
||||
fprintf(stderr, "Cannot read icon data for '%s'\n", path);
|
||||
fwprintf(stderr, L"Cannot read icon data for '%ls'\n", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -641,6 +681,9 @@ bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId,
|
||||
}
|
||||
|
||||
bool ResourceUpdater::SetIcon(const WCHAR* path, const LANGID& langId) {
|
||||
if (iconBundleMap_[langId].iconBundles.empty()) {
|
||||
return SetIcon(path, langId, kDefaultIconBundle);
|
||||
}
|
||||
UINT iconBundle = iconBundleMap_[langId].iconBundles.begin()->first;
|
||||
return SetIcon(path, langId, iconBundle);
|
||||
}
|
||||
@@ -758,6 +801,15 @@ bool ResourceUpdater::Commit() {
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& rcDataLangPair : rcDataLngMap_) {
|
||||
for (const auto&rcDataMap : rcDataLangPair.second) {
|
||||
if (!UpdateResourceW(ru.Get(), RT_RCDATA, reinterpret_cast<LPWSTR>(rcDataMap.first),
|
||||
rcDataLangPair.first, (LPVOID)rcDataMap.second.data(), rcDataMap.second.size())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& iLangIconInfoPair : iconBundleMap_) {
|
||||
auto langId = iLangIconInfoPair.first;
|
||||
auto maxIconId = iLangIconInfoPair.second.maxIconId;
|
||||
@@ -860,6 +912,19 @@ BOOL CALLBACK ResourceUpdater::OnEnumResourceLanguage(HANDLE hModule, LPCWSTR lp
|
||||
instance->iconBundleMap_[wIDLanguage].iconBundles[iconId] = nullptr;
|
||||
break;
|
||||
}
|
||||
case reinterpret_cast<ptrdiff_t>(RT_RCDATA): {
|
||||
const auto moduleHandle = HMODULE(hModule);
|
||||
HRSRC hResInfo = FindResource(moduleHandle, lpszName, lpszType);
|
||||
DWORD cbResource = SizeofResource(moduleHandle, hResInfo);
|
||||
HGLOBAL hResData = LoadResource(moduleHandle, hResInfo);
|
||||
|
||||
const auto *pResource = (const BYTE *)LockResource(hResData);
|
||||
const auto resId = reinterpret_cast<ptrdiff_t>(lpszName);
|
||||
instance->rcDataLngMap_[wIDLanguage][resId] = std::vector<BYTE>(pResource, pResource + cbResource);
|
||||
|
||||
UnlockResource(hResData);
|
||||
FreeResource(hResData);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -883,12 +948,27 @@ BOOL CALLBACK ResourceUpdater::OnEnumResourceManifest(HMODULE hModule, LPCTSTR l
|
||||
HGLOBAL hResData = LoadResource(hModule, hResInfo);
|
||||
const BYTE *pResource = (const BYTE *)LockResource(hResData);
|
||||
|
||||
// FIXME(zcbenz): Do a real UTF string convertion.
|
||||
int len = strlen(reinterpret_cast<const char*>(pResource));
|
||||
std::wstring manifestStringLocal(pResource, pResource + len);
|
||||
size_t found = manifestStringLocal.find(L"requestedExecutionLevel");
|
||||
size_t end = manifestStringLocal.find(L"uiAccess");
|
||||
|
||||
instance->originalExecutionLevel_ = manifestStringLocal.substr(found +31 , end - found - 33);
|
||||
// FIXME(zcbenz): Strip the BOM instead of doing string search.
|
||||
size_t start = manifestStringLocal.find(L"<?xml");
|
||||
if (start > 0) {
|
||||
manifestStringLocal = manifestStringLocal.substr(start);
|
||||
}
|
||||
|
||||
// Support alternative formatting, such as using " vs ' and level="..." on another line
|
||||
size_t found = manifestStringLocal.find(L"requestedExecutionLevel");
|
||||
size_t level = manifestStringLocal.find(L"level=\"", found);
|
||||
size_t end = manifestStringLocal.find(L"\"", level + 7);
|
||||
if (level < 0)
|
||||
{
|
||||
level = manifestStringLocal.find(L"level=\'", found);
|
||||
end = manifestStringLocal.find(L"\'", level + 7);
|
||||
}
|
||||
|
||||
instance->originalExecutionLevel_ = manifestStringLocal.substr(level + 7, end - level - 7);
|
||||
|
||||
// also store original manifestString
|
||||
instance->manifestString_ = manifestStringLocal;
|
||||
|
||||
@@ -109,6 +109,9 @@ class ResourceUpdater {
|
||||
typedef std::map<WORD, StringTable> StringTableMap;
|
||||
typedef std::map<LANGID, VersionInfo> VersionStampMap;
|
||||
typedef std::map<UINT, std::unique_ptr<IconsValue>> IconTable;
|
||||
typedef std::vector<BYTE> RcDataValue;
|
||||
typedef std::map<ptrdiff_t, RcDataValue> RcDataMap;
|
||||
typedef std::map<LANGID, RcDataMap> RcDataLangMap;
|
||||
|
||||
struct IconResInfo {
|
||||
UINT maxIconId = 0;
|
||||
@@ -131,6 +134,7 @@ class ResourceUpdater {
|
||||
bool SetFileVersion(unsigned short v1, unsigned short v2, unsigned short v3, unsigned short v4);
|
||||
bool ChangeString(WORD languageId, UINT id, const WCHAR* value);
|
||||
bool ChangeString(UINT id, const WCHAR* value);
|
||||
bool ChangeRcData(UINT id, const WCHAR* pathToResource);
|
||||
const WCHAR* GetString(WORD languageId, UINT id);
|
||||
const WCHAR* GetString(UINT id);
|
||||
bool SetIcon(const WCHAR* path, const LANGID& langId, UINT iconBundle);
|
||||
@@ -158,6 +162,7 @@ class ResourceUpdater {
|
||||
VersionStampMap versionStampMap_;
|
||||
StringTableMap stringTableMap_;
|
||||
IconTableMap iconBundleMap_;
|
||||
RcDataLangMap rcDataLngMap_;
|
||||
};
|
||||
|
||||
class ScopedResourceUpdater {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2017 GitHub, Inc. All rights reserved.
|
||||
// Use of this source code is governed by MIT license that can be found in the
|
||||
// LICENSE file.
|
||||
|
||||
#ifndef SRC_VERSION_H_
|
||||
#define SRC_VERSION_H_
|
||||
|
||||
#define RCEDIT_MAJOR_VERSION 0
|
||||
#define RCEDIT_MINOR_VERSION 2
|
||||
#define RCEDIT_PATCH_VERSION 0
|
||||
|
||||
#ifndef RCEDIT_TAG
|
||||
# define RCEDIT_TAG ""
|
||||
#endif
|
||||
|
||||
#ifndef RCEDIT_STRINGIFY
|
||||
#define RCEDIT_STRINGIFY(n) RCEDIT_STRINGIFY_HELPER(n)
|
||||
#define RCEDIT_STRINGIFY_HELPER(n) #n
|
||||
#endif
|
||||
|
||||
#define RCEDIT_VERSION_STRING RCEDIT_STRINGIFY(RCEDIT_MAJOR_VERSION) "." \
|
||||
RCEDIT_STRINGIFY(RCEDIT_MINOR_VERSION) "." \
|
||||
RCEDIT_STRINGIFY(RCEDIT_PATCH_VERSION) \
|
||||
RCEDIT_TAG
|
||||
|
||||
#define RCEDIT_VERSION "v" RCEDIT_VERSION_STRING
|
||||
|
||||
#endif // SRC_VERSION_H_
|
||||
Reference in New Issue
Block a user