Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

продолжаем разговор..

6 views
Skip to first unread message

Alexey Fayans

unread,
Dec 3, 2005, 11:58:55 AM12/3/05
to
Hi there, All!

Теперь появилась другая проблема. Библиотеке передается переменная типа record,
поля которой библиотека должна изменять. Hо почему-то у нее возникают какие-то
проблемы с этим. Hапример, есть такой код:

FillChar(HeaderData, SizeOf(HeaderData), #0);
N := RARReadHeaderEx(Handle, HeaderData);
if N = 0 then
begin
WideCharToMultiByte(CP_OEMCP, 0, @HeaderData.FileNameW, -1, @PathBuf, 256,
@DefChar, nil);
Write('Testing ', PathBuf, ' (', HeaderData.FileName, ') .. ');
if RARProcessFile(Handle, RAR_TEST, nil, nil) = 0 then
WriteLn('OK')
else
WriteLn('FAIL');
end;

По идее, в HeaderData.FileName должно содержаться имя файла в OEM кодировке, а
в HeaderData.FileNameW - юникод. У меня же почему-то в HeaderData.FileNameW имя
в OEM кодировке, а в HeaderData.FileName вообще ничего. Причем опять же,
проблема только с VP. Если собирать фрипаскалем, все работает как надо. Я
подумал что проблема может быть в aliging-е. Поигрался в FPC с {$ALIGNRECORDS
n} и убедился, что при любом n все работает нормально (префикс packed убирал
специально). Вот юнит:

=== Starting UnRAR.pas ===
// Delphi interface unit for UnRAR.dll
// Translated from unrar.h
// Use Delphi 2.0 and higher to compile this module
//
// Ported to Delphi by Eugene Kotlyarov, fidonet: 2:5058/26.9 e...@oris.ru
// Fixed version by Alexey Torgashin <ale...@mail.ru>, 2:5020/604.24@fidonet
//
// Revisions:
// Aug 2001 - changed call convention for TChangeVolProc and TProcessDataProc
// - added RARGetDllVersion function, see comment below
//
// Jan 2002 - Added RARSetCallback // eugene
//
// Oct 2002 - Added RARHeaderDataEx, RAROpenArchiveDataEx // eugene

{$IFDEF Open32}
{&cdecl+}
{$ELSE}
{&StdCall+}
{$ENDIF Open32}
{&SmartLink+,OrgName+,X+,Z+,Use32-}

unit UnRAR;

interface

uses Windows;

const
ERAR_END_ARCHIVE = 10;
ERAR_NO_MEMORY = 11;
ERAR_BAD_DATA = 12;
ERAR_BAD_ARCHIVE = 13;
ERAR_UNKNOWN_FORMAT = 14;
ERAR_EOPEN = 15;
ERAR_ECREATE = 16;
ERAR_ECLOSE = 17;
ERAR_EREAD = 18;
ERAR_EWRITE = 19;
ERAR_SMALL_BUF = 20;
ERAR_UNKNOWN = 21;

RAR_OM_LIST = 0;
RAR_OM_EXTRACT = 1;

RAR_SKIP = 0;
RAR_TEST = 1;
RAR_EXTRACT = 2;

RAR_VOL_ASK = 0;
RAR_VOL_NOTIFY = 1;

RAR_DLL_VERSION = 3;

UCM_CHANGEVOLUME = 0;
UCM_PROCESSDATA = 1;
UCM_NEEDPASSWORD = 2;

type
RARHeaderData = packed record
ArcName: packed array[0..Pred(260)] of Char;
FileName: packed array[0..Pred(260)] of Char;
Flags: UINT;
PackSize: UINT;
UnpSize: UINT;
HostOS: UINT;
FileCRC: UINT;
FileTime: UINT;
UnpVer: UINT;
Method: UINT;
FileAttr: UINT;
CmtBuf: PChar;
CmtBufSize: UINT;
CmtSize: UINT;
CmtState: UINT;
end;

RARHeaderDataEx = packed record
ArcName: packed array [0..1023] of Char;
ArcNameW: packed array [0..1023] of WideChar;
FileName: packed array [0..1023] of Char;
FileNameW: packed array [0..1023] of WideChar;
Flags: UINT;
PackSize: UINT;
PackSizeHigh: UINT;
UnpSize: UINT;
UnpSizeHigh: UINT;
HostOS: UINT;
FileCRC: UINT;
FileTime: UINT;
UnpVer: UINT;
Method: UINT;
FileAttr: UINT;
CmtBuf: PChar;
CmtBufSize: UINT;
CmtSize: UINT;
CmtState: UINT;
Reserved: packed array [0..1023] of UINT;
end;

RAROpenArchiveData = packed record
ArcName: PChar;
OpenMode: UINT;
OpenResult: UINT;
CmtBuf: PChar;
CmtBufSize: UINT;
CmtSize: UINT;
CmtState: UINT;
end;

RAROpenArchiveDataEx = packed record
ArcName: PChar;
ArcNameW: PWideChar;
OpenMode: UINT;
OpenResult: UINT;
CmtBuf: PChar;
CmtBufSize: UINT;
CmtSize: UINT;
CmtState: UINT;
Flags: UINT;
Reserved: packed array [0..31] of UINT;
end;

TUnrarCallback = function(Msg: UINT; UserData, P1, P2: Longint): Longint;

function RAROpenArchive(var ArchiveData: RAROpenArchiveData): THandle;
function RAROpenArchiveEx(var ArchiveData: RAROpenArchiveDataEx): THandle;
function RARCloseArchive(hArcData: THandle): Longint;
function RARReadHeader(hArcData: THandle; var HeaderData: RARHeaderData):
Longint;
function RARReadHeaderEx(hArcData: THandle; var HeaderData: RARHeaderDataEx):
Longint;
function RARProcessFile(hArcData: THandle; Operation: Longint; DestPath,
DestName: PChar): Longint;
function RARProcessFileW(hArcData: THandle; Operation: Longint; DestPath,
DestName: PWideChar): Longint;
procedure RARSetCallback(hArcData: THandle; UnrarCallback: TUnrarCallback;
UserData: Longint);
procedure RARSetPassword(hArcData: THandle; Password: PChar);

// obsolete functions
type
TChangeVolProc = function(ArcName: PChar; Mode: Longint): Longint;
TProcessDataProc = function(Addr: PUChar; Size: Longint): Longint;

procedure RARSetChangeVolProc(hArcData: THandle; ChangeVolProc:
TChangeVolProc);
procedure RARSetProcessDataProc(hArcData: THandle; ProcessDataProc:
TProcessDataProc);

implementation

function RAROpenArchive; external;
function RAROpenArchiveEx; external;
function RARCloseArchive; external;
function RARReadHeader; external;
function RARReadHeaderEx; external;
function RARProcessFile; external;
function RARProcessFileW; external;
procedure RARSetCallback; external;
procedure RARSetPassword; external;
procedure RARSetChangeVolProc; external;
procedure RARSetProcessDataProc; external;

end.
=== End of UnRAR.pas ===

Что я делаю не так?


Alexey Fayans

unread,
Dec 10, 2005, 6:50:58 AM12/10/05
to
Hi there, All!

On 03 Dec 2005 19:58 I wrote you:

AF> Теперь появилась другая проблема. Библиотеке передается переменная
AF> типа record, поля которой библиотека должна изменять. Hо почему-то у
AF> нее возникают какие-то проблемы с этим. Hапример, есть такой код:

Я в шоке. В общем, есть описание струтуры:

struct RARHeaderDataEx
{
char ArcName[1024];
wchar_t ArcNameW[1024];
char FileName[1024];
wchar_t FileNameW[1024];
unsigned int Flags;
unsigned int PackSize;
unsigned int PackSizeHigh;
unsigned int UnpSize;
unsigned int UnpSizeHigh;
unsigned int HostOS;
unsigned int FileCRC;
unsigned int FileTime;
unsigned int UnpVer;
unsigned int Method;
unsigned int FileAttr;
char *CmtBuf;
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
unsigned int Reserved[1024];
};

В паскалевском юните это описано так:

TRARHeaderDataEx = packed record


ArcName: packed array [0..1023] of Char;
ArcNameW: packed array [0..1023] of WideChar;
FileName: packed array [0..1023] of Char;
FileNameW: packed array [0..1023] of WideChar;
Flags: UINT;
PackSize: UINT;
PackSizeHigh: UINT;
UnpSize: UINT;
UnpSizeHigh: UINT;
HostOS: UINT;
FileCRC: UINT;
FileTime: UINT;
UnpVer: UINT;
Method: UINT;
FileAttr: UINT;
CmtBuf: PChar;
CmtBufSize: UINT;
CmtSize: UINT;
CmtState: UINT;
Reserved: packed array [0..1023] of UINT;
end;

Это нормально работает, если собирать ФриПаскалем. Если же собирать
Виртуалпаскалем, получается следующая картина: данные, которые должны быть
записаны в FileName, записываются в FileNameW. Hа лицо сдвиг на 1024 байта
после поля ArcNameW. Увеличиваем размер ArcNameW до 2048 байт - и ура, все
работает. Как это объяснить? Это в Си такой Align странный? Можно ли как-то
по-человечески это обходить в виртуалпаскале?


Alexey Fayans

unread,
Dec 10, 2005, 11:31:52 AM12/10/05
to
Hi there, All!

On 10 Dec 2005 14:50 I wrote you:

AF> Это нормально работает, если собирать ФриПаскалем. Если же собирать
AF> Виртуалпаскалем, получается следующая картина: данные, которые должны
AF> быть записаны в FileName, записываются в FileNameW. Hа лицо сдвиг на
AF> 1024 байта после поля ArcNameW. Увеличиваем размер ArcNameW до 2048
AF> байт - и ура, все работает. Как это объяснить? Это в Си такой Align
AF> странный? Можно ли как-то по-человечески это обходить в
AF> виртуалпаскале?

Я прозрел. WideChar должен занимать два байта, а не один. VP'шный RTL не
перестает меня удивлять.


0 new messages