2014-12-15 2 views
3

В DLL Delphi необходимо установить вызывающего абонента - это может быть простой «.exe» или модуль времени выполнения СУБД, что означает, что он должен получить команду, которая выполняется в этом процессе.Получить DLL-информацию о вызывающем абоненте в Delphi

Я знаю, что CmdLine не будет работать, и, вероятно, ParamStr (0), и не могут использовать методы, основанные «главное окно», как вызывающему иногда нет окна. Я подозреваю, что GetModuleHandle является отправной точкой, но ему нужна помощь, чтобы добраться оттуда до исполнения команды.

+0

Почему вы не можете просто указать своему абоненту информацию, которую вам нужно знать в параметре? –

+0

Вы должны более точно определить «вызывающий». –

ответ

1

Фактически ParamStr(0) будет работать нормально. Именно в Windows реализован вызов функции API GetModuleFileName, передавая значение 0 в качестве дескриптора модуля. Это возвращает имя файла, связанное с основным исполняемым модулем. Это работает одинаково независимо от того, что вызов выполняется из библиотеки DLL или основного исполняемого файла.

Нам не нужно вникать в реализацию, если мы доверяем документации Delphi. По общему признанию, это иногда может быть рискованным делом! Документация ParamStr говорит:

ParamStr (0) возвращает путь и имя файла с исполняемой программой (например, C:\TEST\MYPROG.EXE).

Если вам нужно знать аргументы, которые были переданы исполняемому процессу, вы можете использовать ParamStr, передавая индексы больше нуля. Или вы можете позвонить GetCommandLine и самостоятельно проанализировать командную строку.

Остерегайтесь того, что GetCommandLine не всегда будет иметь тот же исполняемый файл, что и имя GetModuleFileName. documentation говорит:

имя исполняемого файла в командной строке, что операционная система обеспечивает процесс не обязательно идентичен, что в командной строке, что вызывающий процесс дает функцию CreateProcess. Операционная система может предусматривать полный путь к исполняемому имени, которое предоставляется без полного пути.

Все это чувствует себя немного грязным. Возможно, было бы проще экспортировать функцию инициализации из DLL и потребовать от вызывающих абонентов передать любую необходимую вам информацию.

+0

David, Это была «проверка документации Delphi», которая вызвала этот вопрос. Эти документы говорят, что глобальная переменная «CmdLine» недопустима в DLL - и это заставило меня поверить, что «GetModuleFileName» не используется (т. Е. Для получения необходимой информации потребуется другая серия тайных вызовов WinAPI). Кстати, причина, по которой я не могу спросить, что вызывающий абонент идентифицирует себя, заключается в том, что вызовы будут поступать из кода, который может быть перекомпилирован, для размещения изменений и кода в течение десятилетия, который больше не подлежит изменению (в то время как DLL API является заменой для бывшего, который не нужно было знать). –

+0

Если вы сомневаетесь, всегда можете обратиться к исходному коду. Что я и сделал. Итак, теперь вы можете доверять ParamStr (0). –

+0

... Если вы не начинаете использовать так называемое издание «Стартер», в этом случае у вас нет выбора, кроме как полагаться на документацию (или спрашивать кого-то другого). Просто говорю. ;) – Deltics

4

Я создал тестовую библиотеку DLL:

library Project2; 

uses 
    System.SysUtils, System.Classes, Vcl.Forms, Vcl.Dialogs, Winapi.Windows; 

{$R *.res} 

procedure DoStuff; stdcall; 
begin 
    ShowMessage(
      'ParamStr(0): '+ParamStr(0)+#13#10+ 
      'GetCommandLine: : '+GetCommandLine); 
end; 

exports 
    DoStuff; 
begin 
end. 

, а затем вызвать его из тестового приложения:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    module: HMODULE; 
    doStuff: procedure; stdcall; 
begin 
    module := LoadLibrary('D:\Temp\Win32\Debug\Project2.dll'); 
    if module = 0 then 
     RaiseLastOSError; 
    try 
     doStuff := GetProcAddress(module, 'DoStuff'); 

     if @doStuff = nil then 
      raise Exception.Create('Could not find export "DoStuff"'); 

     DoStuff; 
    finally 
     FreeLibrary(module); 
    end; 
end; 

И видит командную строку, используя как:

  • ParamStr(0)
  • GetCommandLine

enter image description here

GetCommandLine явно показывает всю командную строку, в то время как ParamStr(0) (по определению) только процесс исполняемым путь.