- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试以编程方式更改 DLL 文件的 VersionInfo 属性。我用过this article作为引用。
#include <iostream>
#include <stdio.h>
#include <windows.h>
int main(int argc, char** argv) {
LPCTSTR lpszFile = "E:\\_test\\rand_test\\test.dll";
DWORD dwHandle,
dwSize;
struct {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// determine the size of the resource information
dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);
if (0 < dwSize)
{
unsigned char* lpBuffer = (unsigned char*) malloc(dwSize);
// Get whole VersionInfo resource/structure
GetFileVersionInfo(lpszFile, 0, dwSize, lpBuffer);
char strSubBlock[37]; // fits "\\StringFileInfo\\xxxxxxxx\\CompanyName\0"
LPTSTR pValueBuffer;
HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);
if (NULL != hResource)
{
UINT uTemp;
// get the language information
if (!VerQueryValue(lpBuffer, "\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &uTemp) != FALSE)
{
printf("Error 1\n");
return 1;
}
sprintf(strSubBlock, "\\StringFileInfo\\%04x%04x\\CompanyName", lpTranslate->wLanguage, lpTranslate->wCodePage);
if (!VerQueryValue(lpBuffer, (LPTSTR) ((LPCTSTR) strSubBlock), (LPVOID *) &pValueBuffer, &uTemp)) {
printf("Error 2\n");
return 1;
}
// PROBLEM!!!
// (pValueBuffer-lpBuffer) is 0x438 (longer than the Versioninfo resource!) but should be 0xB8
// so, pValueBuffer does not point to the actual company name.
ZeroMemory(pValueBuffer, strlen(pValueBuffer) * sizeof(TCHAR));
strcpy(pValueBuffer, "My Company, Inc."); // String may only become smaller or equal, never bigger than strlen(pValueBuffer)
if (UpdateResource(hResource,
RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
lpTranslate->wLanguage, // or 0
lpBuffer,
dwSize) != FALSE)
{
EndUpdateResource(hResource, FALSE);
}
}
free(lpBuffer);
}
return 0;
}
我想我已经理解了代码所做的一切。计划是读取 Versioninfo block ,然后找到例如的位置CompanyName 使用 VerQueryValue
,然后更改数据,然后使用 UpdateResource 将其写回。
但是有一个问题:VerQueryValue
应该输出 CompanyName 字符串所在的位置。但相反,它给出了一个指针位置,该位置距离几百个字节,因此它指向 VersionInfo 结构之外的某个位置。
我做错了什么以及如何让它发挥作用?
(另外,有人知道是否有一种更优雅的方法来完成这项任务,甚至可能消除字符串必须小于或等于原始字符串的限制?)
最佳答案
版本资源这是序列化树。如果你想修改它 - 你需要将其反序列化为内存中的树结构,修改节点,然后序列化到新内存。
尽管msdn中定义了几个Version Information Structures ,实际上它们都有共同的格式
struct RsrcHeader
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
// aligned on 4*n
// BYTE Value[wValueLength]; // if (wType == 0)
// or
// WCHAR Value[wValueLength]; // if (wType == 1)
// every element aligned on 4*n
// RsrcHeader childs[];
};
因此可以编写通用的解析和序列化程序
#if DBG
#define DBG_OPT(x) _CRT_UNPARENTHESIZE(x)
#else
#define DBG_OPT(x)
#endif
class RsrcNode
{
struct RsrcHeader
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
};
C_ASSERT(sizeof(RsrcHeader) == 6);
RsrcNode* _first, *_next;
PCWSTR _name;
const void* _pvValue;
ULONG _cbValue;
WORD _wValueLength;
WORD _wType;
DBG_OPT((PCSTR _prefix)); // only for debug output
public:
bool ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix);
RsrcNode(DBG_OPT((PCSTR prefix = "")))
: _next(0), _first(0) DBG_OPT((, _prefix(prefix)))
{
}
~RsrcNode();
bool IsStringValue() const
{
return _wType;
}
const void* getValue(ULONG& cb)
{
cb = _cbValue;
return _pvValue;
}
void setValue(const void* pv, ULONG cb)
{
_pvValue = pv, _cbValue = cb;
_wValueLength = (WORD)(_wType ? cb / sizeof(WCHAR) : cb);
}
RsrcNode* find(const PCWSTR strings[], ULONG n);
ULONG GetSize() const;
PVOID Store(PVOID buf, ULONG* pcb) const;
};
bool RsrcNode::ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix)
{
union {
PVOID pv;
RsrcHeader* ph;
ULONG_PTR up;
PCWSTR sz;
};
pv = buf;
if (size < sizeof(RsrcHeader) || (up & 3))
{
return false;
}
WORD wType = ph->wType;
ULONG wValueLength = ph->wValueLength, wLength = ph->wLength;
ULONG cbValue = 0;
switch (wType)
{
case 1:
cbValue = wValueLength * sizeof(WCHAR);
break;
case 0:
cbValue = wValueLength;
break;
default:
return false;
}
*pLength = wLength;
if (wLength > size || wLength < sizeof(RsrcHeader) || cbValue >= (wLength -= sizeof(RsrcHeader)))
{
return false;
}
wLength -= cbValue;
sz = ph->szKey, _name = sz;
do
{
if (wLength < sizeof(WCHAR))
{
return false;
}
wLength -= sizeof(WCHAR);
} while (*sz++);
DbgPrint("%s%S {\n", prefix, _name);
if (up & 3)
{
if (wLength < 2)
{
return false;
}
up += 2, wLength -= 2;
}
_wType = wType, _wValueLength = (WORD)wValueLength, _cbValue = cbValue, _pvValue = pv;
if (wValueLength && wType)
{
if (sz[wValueLength - 1])
{
return false;
}
DbgPrint("%s\t%S\n", prefix, sz);
}
if (wLength)
{
if (!*--prefix) return false;
up += wValueLength;
do
{
if (up & 3)
{
if (wLength < 2)
{
return false;
}
up += 2;
if (!(wLength -= 2))
{
break;
}
}
if (RsrcNode* node = new RsrcNode(DBG_OPT((prefix))))
{
node->_next = _first, _first = node;
if (node->ParseResourse(ph, wLength, &size, prefix))
{
continue;
}
}
return false;
} while (up += size, wLength -= size);
prefix++;
}
DbgPrint("%s}\n", prefix);
return true;
}
RsrcNode::~RsrcNode()
{
if (RsrcNode* next = _first)
{
do
{
RsrcNode* cur = next;
next = next->_next;
delete cur;
} while (next);
}
DBG_OPT((DbgPrint("%s%S\n", _prefix, _name)));
}
RsrcNode* RsrcNode::find(const PCWSTR strings[], ULONG n)
{
PCWSTR str = *strings++;
if (!str || !wcscmp(str, _name))
{
if (!--n)
{
return this;
}
if (RsrcNode* next = _first)
{
do
{
if (RsrcNode* p = next->find(strings, n))
{
return p;
}
} while (next = next->_next);
}
}
return 0;
}
ULONG RsrcNode::GetSize() const
{
ULONG size = sizeof(RsrcHeader) + (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR);
if (_cbValue)
{
size = ((size + 3) & ~3) + _cbValue;
}
if (RsrcNode* next = _first)
{
do
{
size = ((size + 3) & ~3) + next->GetSize();
} while (next = next->_next);
}
return size;
}
PVOID RsrcNode::Store(PVOID buf, ULONG* pcb) const
{
union {
RsrcHeader* ph;
ULONG_PTR up;
PVOID pv;
};
pv = buf;
ph->wType = _wType;
ph->wValueLength = _wValueLength;
ULONG size = (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR), cb;
memcpy(ph->szKey, _name, size);
up += (size += sizeof(RsrcHeader));
if (_cbValue)
{
up = (up + 3) & ~3;
memcpy(pv, _pvValue, _cbValue);
up += _cbValue;
size = ((size + 3) & ~3) + _cbValue;
}
if (RsrcNode* next = _first)
{
do
{
up = (up + 3) & ~3;
pv = next->Store(pv, &cb);
size = ((size + 3) & ~3) + cb;
} while (next = next->_next);
}
reinterpret_cast<RsrcHeader*>(buf)->wLength = (WORD)size;
*pcb = size;
return pv;
}
通过这个辅助结构,我们可以通过以下方式更新版本:
#include "VerHlp.h"
BOOL UpdateVersion(PVOID pvVersion, ULONG cbVersion, PVOID& pvNewVersion, ULONG& cbNewVersion)
{
BOOL fOk = FALSE;
char prefix[16];
memset(prefix, '\t', sizeof(prefix));
prefix[RTL_NUMBER_OF(prefix) - 1] = 0;
*prefix = 0;
if (RsrcNode* node = new RsrcNode)
{
if (node->ParseResourse(pvVersion, cbVersion, &cbVersion, prefix + RTL_NUMBER_OF(prefix) - 1))
{
static const PCWSTR str[] = {
L"VS_VERSION_INFO", L"StringFileInfo", 0, L"CompanyName"
};
if (RsrcNode *p = node->find(str, RTL_NUMBER_OF(str)))
{
if (p->IsStringValue())
{
ULONG cb;
const void* pvCompanyName = p->getValue(cb);
DbgPrint("CompanyName: %S\n", pvCompanyName);
static WCHAR CompanyName[] = L"[ New Company Name ]";
if (cb != sizeof(CompanyName) ||
memcmp(pvCompanyName, CompanyName, sizeof(CompanyName)))
{
p->setValue(CompanyName, sizeof(CompanyName));
cbVersion = node->GetSize();
if (pvVersion = LocalAlloc(0, cbVersion))
{
node->Store(pvVersion, &cbNewVersion);
pvNewVersion = pvVersion;
fOk = TRUE;
}
}
}
}
}
delete node;
}
return fOk;
}
struct EnumVerData
{
HANDLE hUpdate;
BOOL fDiscard;
};
BOOL CALLBACK EnumResLangProc(HMODULE hModule,
PCWSTR lpszType,
PCWSTR lpszName,
WORD wIDLanguage,
EnumVerData* Ctx
)
{
if (HRSRC hResInfo = FindResourceExW(hModule, lpszType, lpszName, wIDLanguage))
{
if (HGLOBAL hg = LoadResource(hModule, hResInfo))
{
if (ULONG size = SizeofResource(hModule, hResInfo))
{
if (PVOID pv = LockResource(hg))
{
if (UpdateVersion(pv, size, pv, size))
{
if (UpdateResource(Ctx->hUpdate, lpszType, lpszName, wIDLanguage, pv, size))
{
Ctx->fDiscard = FALSE;
}
LocalFree(pv);
}
}
}
}
}
return TRUE;
}
ULONG UpdateVersion(PCWSTR FileName)
{
ULONG dwError = NOERROR;
EnumVerData ctx;
if (ctx.hUpdate = BeginUpdateResource(FileName, FALSE))
{
ctx.fDiscard = TRUE;
if (HMODULE hmod = LoadLibraryExW(FileName, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE))
{
if (!EnumResourceLanguages(hmod, RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
(ENUMRESLANGPROCW)EnumResLangProc, (LONG_PTR)&ctx))
{
dwError = GetLastError();
}
FreeLibrary(hmod);
}
else
{
dwError = GetLastError();
}
if (!dwError && !EndUpdateResourceW(ctx.hUpdate, ctx.fDiscard))
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
return dwError;
}
关于c - 以编程方式更改外部 DLL 的 VersionInfo,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53916682/
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!