【问题标题】:Convert one delphi code line to c++将一行delphi代码转换为c++
【发布时间】:2012-04-13 23:24:18
【问题描述】:

如何用 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++代码(希望其他都OK)

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;

在这里我得到信息或绑定文件...

变量 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 = ???

【问题讨论】:

  • Delphi 短字符串 (String[50]) 的大小为 51 个字节,因为 sFileName[0] 保存了字符串的长度。
  • 您需要使用... 发布一些您省略的代码。在某处,内容被分配给 sZdData 并带有分配,并且在该缺失代码中还有其他可用信息。

标签: c++ delphi


【解决方案1】:
  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 级别,它们的行为相同。

【讨论】:

  • 这根本不是 Delphi 代码所做的,也不是 C++ 代码应该做的。没有memcpy 参与;它是指针sZdData 引用的内容的直接类型转换为记录。 IOW,它将TSettings 变量的内容分配给位于sZdData[i]s 地址的内存块(创建指向同一位置的类型化指针)。根本不涉及movecopy;在发布的代码中,SettingssZdData[i] 都引用了相同的内存块。
  • 我添加了所有代码,以帮助你们理解我需要什么,谢谢你们的回答
  • 请注意,帖子说“基本上”。它旨在为读者简化它。实际上它是 inline rep ;如果需要,可以使用 movsd + movsw/b 语句,但我不知道如何为 C 显示这一点。而且你的描述是错误的。它将块 /TO/ 的内容分配给 TSettings 值,而不是相反。在我看到的代码中(在添加之前),也无法找出 szddata 指向的内容。我认为这是一个不相关的文件缓冲区。
  • 我发布了一些代码来理解一切......所以你的代码会和上面的 delphi 代码一样吗?如果是这样,谢谢 man bedankt :P
  • 你说得对,我的措辞有误。我的评论应该是“将sZdData[i]s 地址的内存块的内容分配给TSettings 变量”。这并没有改变绝对没有涉及移动或复制的事实;将指针设置为指向与另一个指针相同的内存不涉及复制或移动。这是对指针的简单地址分配。 :) 另请注意,我没有投反对票;我只是评论说你的答案不太正确。
【解决方案2】:

在 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

顺便说一下,注意对齐。由于项目之间的差距,总结构大小可能会超出您的预期。

【讨论】:

  • 顺便说一句,几乎所有 32/64 位编译器也将接受您在 Pascal 中的等效代码。这个例子很复杂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-08
  • 2015-11-27
  • 2013-06-30
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 2012-05-04
相关资源
最近更新 更多