"Виртуальная библиотека Delphi" - читать интересную книгу автора

Стандартная технология доступа к ресурсам

Для компиляции примера надо создать на диске перечисленные исходные файлы (все в текстовом формате). Я не привел примеров для ресурсов типа BitMap`ов, Icon`ов и курсоров, поскольку обращения к ним достаточно тривиальны и не содержат каких-либо неоднозначностей, и, во-вторых, они (декларации ресурсов) недостаточно компактно записываются в виде текста.

Файл `#_Msg.Ini`

Список строк в текстовом файле

msgHello= Здавствуйте !

msgBye= До свидания …

Файл `#_Msg.RC`

Скрипт компилятора ресурсов. В двоичном ресурсе с именем RC1 записана ASCIIz-строка `QWERTY`.

RC1 RCDATA

{

'51 57 45 52 54 59 00'

}

STRINGTABLE

{

1000, "Здравствуйте ."

1001, "До свидания ..."

}

Файл `Proj_L.Dpr`:

Мы используем Delphi как линкер, чтобы дописать стандартный заголовок исполняемых файлов Windows к файлу `#_Msg.Res`. Последний делается компилятором ресурсов из скрипта `#_Msg.RC`. IDE может ругаться при загрузке этого проекта из-за отсутствия секции `uses` —дура.

{$IMAGEBASE $40000000}

{$APPTYPE CONSOLE}

library Proj_L;

{$R #_MSG.RES}

BEGIN

END.

Файл `Make_DLL.Bat`:

Компилируем скрипт `#_Msg.RC` в файл `#_Msg.Res`; компилируем и линкуем проект `Proj_L.Dpr`. Получаем файл `Proj_L.Dll`.

rem –- may be used BRC32 or BRCC32

rem c:\del3\bin\brc32 –r #_msg.rc

c:\del3\bin\brcc32 #_msg.rc

c:\del3\bin\dcc32 /b proj_l.dpr

pause

Файл `Proj.Dpr`

{$APPTYPE GUI}

{$D+,O-,S-,R-,I+,A+,G+}

{$IfOpt D-} {$O+} {$EndIf}


program Proj;


{$IfNDef WIN32}

  error: it works only under Win32

{$EndIf}


uses

  Windows,

  SysUtils,

  Classes;


{//////////////////////////////////////////////}


procedure i_MsgBox( const ACap,AStr:String );

{ service routine: simple message-box }

begin

  Windows.MessageBox( 0, pChar(AStr), pChar(ACap),

    MB_OK or MB_ICONINFORMATION );

end;


{///// TestSList ////}


procedure TestSList;

{ load strings from ini-file via tStringList }

const

  cFName = '#_MSG.INI';

var

  qSList : tStringList;

begin

  qSList := tStringList.Create;

  with qSList do try

    LoadFromFile( ExtractFilePath(ParamStr(0))+cFName );

    i_MsgBox( 'strings collection via VCL:',

      Trim(Values['msghello'])+#13+Trim(Values['MSGBYE']) );

  finally Free;

  end;

end;


{//// TestBuiltInStrRes ////}


RESOURCESTRING

  sMsgHello = 'ЯВЕРТЫяверты';

  sMsgBye = 'явертыЯВЕРТЫ';


procedure TestBuiltInStrRes;

{ load strings from resources via Delphi`s Linker }

begin

  i_MsgBox( 'built-in string resources:', sMsgHello+#13+sMsgBye );

end;


{//////////////////////////////////////////////}


type

  tFH_Method = procedure( AFHandle:tHandle );

{ `AFHandle` must be a handle of instance of image (of memory-map)

  of a PE-file (EXE or DLL) }


procedure i_Call_FH_Method( AProc:tFH_Method );

{ it is wrapper to load and free a instance of binary

  file with resource; also it calls to "AProc()" with

  given instance-handle }

const

  cLibName = 'PROJ_L.DLL';

var

  qFHandle : tHandle;

begin

  qFHandle := Windows.LoadLibrary(

    pChar(ExtractFilePath(ParamStr(0))+cLibName) );

  if qFHandle=0 then

    i_MsgBox( 'Error loading library',

      Format('Code# %xh',[Windows.GetLastError]) )

  else

    try     AProc( qFHandle );

    finally Windows.FreeLibrary( qFHandle );

    end;

end;


{//// TestBinRes_WinAPI ////}


procedure TestBinRes_WinAPI( AFHandle:tHandle );

{ loading binary resource via usual windows-API }

var

  qResH,

  qResInfoH : tHandle;

begin

  qResInfoH := Windows.FindResourceEx( AFHandle , RT_RCDATA, 'RC1', 0 );

  qResH := Windows.LoadResource( AFHandle, qResInfoH );

  try     i_MsgBox( 'binary resource (Win API):',

            pChar(Windows.LockResource(qResH)) );

  finally Windows.FreeResource( qResH );

  end;

end;


{//// TestBinRes_VCLStream ////}


procedure TestBinRes_VCLStream( AFHandle:tHandle );

{ loading binary resource via VCL`s stream }

var

  qResStream : tResourceStream;

begin

  qResStream := tResourceStream.Create( AFHandle, 'RC1', RT_RCDATA );

  try     i_MsgBox( 'binary resource (VCL stream):',

            pChar(qResStream.Memory) );

  finally qResStream.Free;

  end;

end;


{//// TestStrRes_WinAPI ////}


procedure TestStrRes_WinAPI( AFHandle:tHandle );

{ loading string resource via usual windows-API }

const

  cBufSize = 512;

var

  qBuf : array[0..1,0..cBufSize-1]of Char;

begin

  Windows.LoadStringA( AFHandle, 1000, qBuf[0], cBufSize );

  Windows.LoadStringA( AFHandle, 1001, qBuf[1], cBufSize );

  i_MsgBox( 'string resources (Win API):',

    StrPas(qBuf[0])+#13+StrPas(qBuf[1]) );

end;


BEGIN

  TestSList;

  TestBuiltInStrRes;

  i_Call_FH_Method( TestBinRes_WinAPI );

  i_Call_FH_Method( TestBinRes_VCLStream );

  i_Call_FH_Method( TestStrRes_WinAPI );

END.

Замечания:

• Rесурсы частично вынесены во внешнюю DLL только для демонстрации, поскольку большинство вопросов в конференции подразумевает именно такое их использование.

• Если ресурсы слинкованы не в отдельную DLL, а в исполняемый файл проекта, в параметре AFHandle надо везде передавать `0` или значение переменной System.HInstance.

• Вместо функции Windows.FindResource() я предпочитаю FindResourceEx() с лишним явным параметром — `LanguageId`. Дело в том, что первая не всегда находит ресурсы, сделанные борландовскими компиляторами — семантика LanguageId по умолчанию определена MS не совсем однозначно.

• Для однозначности, я явно указал имя функции Windows.LoadStringA(). В NT работает еще функция LoadStringW(), которая возвращает строки UNICODE. В Win95 LoadStringW() возвращает код ошибки `not implemented`.