如何用 C++ 编写该行?
使用delphi代码(不是这里发布的代码),我会将填充一些信息的记录写入exe文件,使用c ++代码,我将读取该记录并将信息传递给结构
这是delphi中的代码
type
TSettings = record
sFileName: String[50];
siInstallFolder: Byte;
bRunFile: Boolean;
...
end;
..
var
i: dword;
sZdData: PChar;
Settings :Tsettings;
begin
....
ZeroMemory(@Settings, sizeof(Tsettings));
settings := Tsettings(Pointer(@sZdData[i])^); // this code to c++
c++代码(希望其余没问题)
struct TSettings{
char sFileName[50];
byte siInstallFolder;
bool bRunFile;
...
} Settings;
...
DWORD i;
LPBYTE sZdData;
ZeroMemory(&Settings, sizeof(TSettings));
Settings = ????? // im failing here i dunno what to do // i need same as in delphi code above
抱歉我的英语不好..:(
这是delphi代码
function GetInfoSettings(FileName: String; // filename from where to get data
var lpData: PChar; // where to write data
var dwSettingsLen: DWORD // returns the length of all bound files
): Boolean;
var
hFile: THandle;
DosHeader: TImageDosHeader;
NtHeaders: TImageNtHeaders;
SectionHeader: TImageSectionHeader;
dwReadBytes, dwOrginalFileSize, dwFileSize, dwSettingsLength: DWORD;
begin
Result := False;
hFile := Createfile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
ReadFile(hFile, DosHeader, sizeof(DosHeader), dwReadBytes, nil);
if dwReadBytes = sizeof(DosHeader) then
begin
SetFilePointer(hFile, DosHeader._lfanew, nil, FILE_BEGIN);
ReadFile(hFile, NtHeaders, sizeof(NtHeaders), dwReadBytes, nil);
if dwReadBytes = sizeof(NtHeaders) then
begin
SetFilePointer(hFile, sizeof(SectionHeader) * (NtHeaders.FileHeader.NumberOfSections -1), nil, FILE_CURRENT);
ReadFile(hFile, SectionHeader, sizeof(SectionHeader), dwReadBytes, nil);
dwOrginalFileSize := SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData;
dwFileSize := GetFileSize(hFile, nil);
dwSettingsLength := dwFileSize - dwOrginalFileSize;
if dwSettingsLength > 0 then
begin
SetFilePointer(hFile, dwOrginalFileSize, nil, FILE_BEGIN);
GetMem(lpData, dwSettingsLength);
ReadFile(hFile, lpData^, dwSettingsLength, dwReadBytes, nil);
if dwReadBytes = dwSettingsLength then
begin
Result := True;
dwSettingsLen := dwSettingsLength;
end;
end;
end;
end;
CloseHandle(hFile);
end;
在这里我得到信息或绑定文件...
var i, // 这里将保存已经完成的字节数.. dwDaSize:双字; // 所有部分之后的数据长度.. dwFilenaam,sFileName :字符串; sZdData:PChar; // 这里将是“EOF”之后的所有数据(所有部分数据的结尾) // 将提取文件的文件名..
Settings: Tsettings;
// writting
hFile: THandle;
lpNumberOfBytesWritten: DWORD;
begin
GetMem(dwFilenaam, MAX_PATH);
GetModuleFileName(GetModuleHandle(nil), dwFilenaam, MAX_PATH);
if GetInfos(dwFilenaam, sZdData, dwDaSize) then
begin
i := 0;
repeat
ZeroMemory(@Settings, sizeof(Tsettings));
settings := Tsettings(Pointer(@sZdData[i])^);
我的尝试(我知道这段代码看起来很垃圾哈哈)也许不是?
bool getSettingsInfo(LPSTR FileName, LPBYTE lpdata, DWORD dwSettingsLen)
{
HANDLE HandleFile ;
DWORD dwReadBytes;
DWORD dwOrginalFileSize;
DWORD dwFileSize;
DWORD dwSettingsLength;
PIMAGE_DOS_HEADER pidh ;
PIMAGE_NT_HEADERS pinh ;
PIMAGE_SECTION_HEADER pish;
return false;
HandleFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, 0,OPEN_EXISTING,0, NULL);
SetFilePointer(HandleFile, 0,0, FILE_BEGIN);
ReadFile(HandleFile, pidh, sizeof(pidh), &dwReadBytes,NULL);
if (dwReadBytes == sizeof(pidh))
{
SetFilePointer(HandleFile, pidh->e_lfanew , NULL, FILE_BEGIN);
ReadFile(HandleFile, pidh,sizeof(pinh), &dwReadBytes, NULL);
if (dwReadBytes == sizeof(pinh))
{
SetFilePointer(HandleFile, sizeof(pish) * (pinh->FileHeader.NumberOfSections -1), NULL, FILE_CURRENT);
ReadFile(HandleFile, pish, sizeof(pinh), &dwReadBytes, NULL);
dwOrginalFileSize = pish->PointerToRawData + pish->SizeOfRawData;
dwFileSize = GetFileSize(HandleFile, NULL);
dwSettingsLength = dwFileSize - dwOrginalFileSize;
if (dwSettingsLength > 0)
{
SetFilePointer(HandleFile, dwOrginalFileSize, NULL, FILE_BEGIN);
realloc(lpdata, dwSettingsLength);
ReadFile(HandleFile, lpdata, dwSettingsLength, &dwReadBytes, NULL);
if (dwReadBytes == dwSettingsLength)
{
return true;
dwSettingsLen = dwSettingsLength;
}
}
}
}
CloseHandle(HandleFile);
}
提取信息的代码...
DWORD i; // here will be saved how much bytes are already done ..
DWORD dwDaSize; // length of data after all sections ..
LPSTR dwFilenaam;
LPBYTE sZdData; // here will be all data after "EOF" (End of all sections data)
LPSTR sFileName;// the filename where the file will be extracted ..
char * Installpath;
char * buffer;
HFILE hFile;
DWORD lpNumberOfBytesWritten;
memset(dwFilenaam,0, MAX_PATH);
GetModuleFileName(GetModuleHandle(NULL), dwFilenaam, MAX_PATH);
if (getSettingsInfo(dwFilenaam, sZdData, dwDaSize) == true)
{
i = 0;
// REPEAT
ZeroMemory(&Settings, sizeof(TSettings));
Settings = ???
struct TSettings{
uchar length ; // shortstrings have an implicit length byte
char sFileName[50];
byte siInstallFolder;
bool bRunFile; // one byte, 1=true, 0=false any other value undefined
...
} Settings;
DWORD i;
LPBYTE sZdData;
ZeroMemory(&Settings, sizeof(TSettings));
literally it is something like
Settings = (struct Settings) (*((void *)&sZDData[i])
essentially it does
memcpy (&sZDData[i],&settings,sizeof(TSettings));
它的作用是获取 sZSdata (@sZDDATA[i]) 第 i 个元素的地址并将其转换为无类型指针。 (相当于 C++ (void*)(&sZDData[i])) )
然后是时髦的部分,取消引用它(^ 作为 pascal 中的后缀运算符,* 作为 C 中的前缀运算符)(本质上是 (void) ptr 指向的地址,一块没有附加长度数据的内存块它)。
当将其分配给设置时,这显然意味着将与左值 (= sizeof(settings)) 大小一样多的字节从该地址移动到左值(设置)中。
这是一个非常时髦的结构,我不确定我以前是否见过它。我检查了 Delphi 和 FPC 中的 asm 级别,它们的行为相同。
C 语言应该比 Delphi 更容易:
typedef struct
{
uchar length ; // shortstrings have an implicit length byte
char sFileName[50];
byte siInstallFolder;
bool bRunFile; // one byte, 1=true, 0=false any other value undefined
...
} TSettings;
TSettings settings;
DWORD i;
LPBYTE sZdData;
settings = *(TSettings*)(&sZdData[i]);
这将调用 memcpy,不是因为转换,而是因为分配 TSettings 结构。如果您使用指向 TSettings 的指针,则无需复制即可访问:
TSettings* pSettings;
DWORD i;
LPBYTE sZdData;
pSettings = (TSettings*)(&sZdData[i]);
printf("%d\n", pSettings->siInstallFolder); // example
顺便说一句,要小心对齐。由于项目之间存在间隙,总结构大小可能超出您的预期。
可能有点晚了,但以防万一有帮助。
寻找紧密的等价物,我们可能会得到类似的结果:
#include <array>
#include <cstdint>
#include <cstring>
struct TSettings
{
std::array<wchar_t,50> sFileName;
std::byte siInstallFolder;
bool bRunFile;
};
uint32_t i;
wchar_t* sZdData;
TSettings Settings;
memset(&Settings, 0, sizeof(TSettings));
Settings = *reinterpret_cast<TSettings*>(&(sZdData[i]));
这是一个稍微详细一点的版本:
#include <array>
#include <cassert>
#include <cstdint>
#include <iostream>
#include <string>
using Buff = std::array<char, 300>;
struct Settings
{
std::array<wchar_t,50> sFileName;
uint8_t siInstallFolder = 0;
bool bRunFile = false;
};
auto write_settings_in_buffer( Buff& buff, const Settings& s, size_t pos=0) -> void
{
assert(buff.size() > sizeof(Settings)+pos);
*reinterpret_cast<Settings*>(buff.data()+pos) = s;
}
auto read_settings_from_buffer( Settings& s, const Buff& buff, size_t pos=0) -> void
{
assert(buff.size() > sizeof(Settings)+pos);
s = *reinterpret_cast<const Settings*>(&(buff.data()[pos]));
}
auto print_settings( const Settings& s) -> void
{
std::wcout <<
s.sFileName.data() << " : " <<
s.siInstallFolder << " - " <<
s.bRunFile << std::endl;
}
auto main() -> int
{
const size_t idx = 5;
Settings origSettings{L"Hi world!", 42, true};
Buff buff;
write_settings_in_buffer(buff, origSettings, idx);
Settings destSetting;
read_settings_from_buffer(destSetting, buff, idx);
print_settings(destSetting);
}