Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Работа с реестром на API


Автор: TeX 27.10.2008, 16:18
Здравствуйте уважаемые !
Пишу сервис, который должен проверять определенные ветки реестра (), на появление "левых" записей.
Подскажите как правильно работать с реестром из сервиса с помощью API. Я нашел похожую тему, но там было только создание и удаление и то , из обычного приложения. Хорошо было бы если примерчик дадите.

Автор: ne0n 27.10.2008, 21:49
TeX, http://delphiworld.narod.ru/base/registry_api.html

Автор: TeX 28.10.2008, 08:45
Цитата(ne0n @ 27.10.2008,  21:49)
TeX, http://delphiworld.narod.ru/base/registry_api.html

Спасибо за ссылку, очень полезная, НО... хотелось бы разобраться как работать с реестром с помощью функций из ntdll.dll.

Автор: ne0n 28.10.2008, 11:53
Цитата(TeX @  28.10.2008,  08:45 Найти цитируемый пост)
Спасибо за ссылку, очень полезная, НО... хотелось бы разобраться как работать с реестром с помощью функций из ntdll.dll.


так и надо было сказать что нужно именно Native Api,  Вообщем  есть очень хорошая книга - 
Справочник по базовым функциям API Windows NT/2000, Гэри Неббет. Есть глава посвященная реестру, в которой все подробно расписано. Но там все прототипы приводяться для C++, для Delphi я вроде не встречал  подоного. При желании перевести не сложно.

Автор: TeX 28.10.2008, 14:43
Цитата(ne0n @ 28.10.2008,  11:53)
так и надо было сказать что нужно именно Native Api,  Вообщем  есть очень хорошая книга - 
Справочник по базовым функциям API Windows NT/2000, Гэри Неббет. Есть глава посвященная реестру, в которой все подробно расписано. Но там все прототипы приводяться для C++, для Delphi я вроде не встречал  подоного. При желании перевести не сложно.

За наводку на книгу, спасибо, найду-почитаю. У JEDI нашел интерфейсный модуль Windows NT Native API   для delphi, в котором описаны все структуры, процедуры и функции. Вот сижу сейчас разбираюсь с этим.

Автор: TeX 30.10.2008, 10:29
Два дня упражнений привели лишь к номальному открытию ветки реестра, а вот с чтением туго.
Подскажите ка работать с функцией

Код

   function NtQueryValueKey(KeyHandle:THandle; 
                                             ValueName:PUNICODE_STRING;
                                             KeyValueInformationClass:KEY_VALUE_INFORMATION_CLASS; 
                                             var KeyValueInformation:PVOID; 
                                             Length:ULONG;
                                             var ResultLength:PULONG):NTSTATUS; stdcall; external ntdll name 'NtQueryValueKey';

Загвоздка в буфере, куда будет помещена информация.
В зависимости  KeyValueInformationClass должны использоваться разные структуры, описания которых в интерфейсном модуле нет. Пришлось самому сделать эту структуру:
Код

PKEY_VALUE_PARTIAL_INFORMATION = ^_KEY_VALUE_PARTIAL_INFORMATION;
 _KEY_VALUE_PARTIAL_INFORMATION = packed record
    TitleIndex:ULONG;
    Type_:ULONG;
    DataLength:ULONG;
    Data:array [0..0] of UCHAR; // Variable length data
 end;
 KEY_VALUE_PARTIAL_INFORMATION=_KEY_VALUE_PARTIAL_INFORMATION;


Вод код процедуры:

Код

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
   KeyName: UNICODE_STRING;
   ValueName: UNICODE_STRING;
   SoftwareKeyHandle: THandle;
   Status: ULONG;
   ObjAttr: OBJECT_ATTRIBUTES;
   Buffer: array of WideChar;
   Key:widestring;
   ValueKey:WideString;
   err:cardinal;
   Data:^KEY_VALUE_PARTIAL_INFORMATION;
   ValueString:UNICODE_STRING;
   DataSize:ULONG;
begin
  Key:=sid; // путь с SID-ом текущего пользователя
  RtlInitUnicodeString(@KeyName,@key[1]);
  RtlInitUnicodeString(@ValueName,'App');
  InitializeObjectAttributes(@ObjAttr, @KeyName, OBJ_CASE_INSENSITIVE,0, nil);
  Status := NtOpenKey(@SoftwareKeyHandle,KEY_QUERY_VALUE,@ObjAttr);
  if not NT_SUCCESS(Status) then
   raise Exception.Create('Error: Couldn''t open registry tree')
   else
    begin
     Status:=NtQueryValueKey(SoftwareKeyHandle,@ValueName, KeyValuePartialInformation,nil,0,@DataSize); // получаем размер данных
     if DataSize <> 0 then
       begin
         data:=AllocMem(sizeof(KEY_VALUE_PARTIAL_INFORMATION));
         Status:=NtQueryValueKey(SoftwareKeyHandle,@ValueName, KeyValuePartialInformation,Data,DataSize,@DataSize); //пытаемся получить значение
         if NT_SUCCESS(status) then
          begin
            if PKEY_VALUE_PARTIAL_INFORMATION(data).Type_ = REG_SZ then
              ShowMessage('ok'); //  <--- Здесь возникает исключение Debugger Fail Notification
          end;
       end;
    end;

  NtClose(SoftwareKeyHandle )
end;



При работе возникает исключение, что-то я неправильно делаю и скорее что-то с выделением памяти, но где не могу понять. smile  Пмогите кодом или советом.

Автор: Riply 31.10.2008, 08:02
Цитата(TeX @  30.10.2008,  10:29 Найти цитируемый пост)
В зависимости  KeyValueInformationClass должны использоваться разные структуры, описания которых в интерфейсном модуле нет


Если мне не изменяет память они все (структуры) есть в MSDN



Цитата(TeX @  30.10.2008,  10:29 Найти цитируемый пост)
Пришлось самому сделать эту структуру


При использовании "системных" функций, отсебятина в определении структур недопустима
(за исключением очень редких случаев)
При переводе структур с С на Delphi, внимательно следи не тлько за размером всей
стр-ры, но и каждого поля в отдельности.

Это было вступление, теперь бегло взглянем на код и ужаснемся smile

Код

Status:=NtQueryValueKey(SoftwareKeyHandle,@ValueName, yValuePartialInformation,nil,0,@DataSize); 
if DataSize <> 0 then


1. Для чего в данной строчке определяется Status ?
2. С чего ты взял, что если NtQueryValueKey отработает с ошибкой, то будет произведена запись
    в DataSize (которая, меду прочим, не инициализирована, но это "к слову") ?
3. Зачем вообще ты пытался получить  DataSize, если после этого выделяешь память
    таким образом data:=AllocMem(sizeof(KEY_VALUE_PARTIAL_INFORMATION)); ?
4. Почему в память размера sizeof(KEY_VALUE_PARTIAL_INFORMATION)
    ты пишешь DataSize байт, а потом еще удивляешся на AV ?
5. Где освобождение памяти ?
6. Почему не используются try/finally ?

Мое IMHO: рановато тебе еще работать с Native-функциями.
Просто приведенный кусок кода показывает полное непонимание его автором
того что в нем (коде) происходит.
Дружеский совет: почитай книжки (акцентируй внимание на работе с памятью и с ошибками). 

Автор: TeX 31.10.2008, 09:01
Цитата
Мое IMHO: рановато тебе еще работать с Native-функциями.
Просто приведенный кусок кода показывает полное непонимание его автором
того что в нем (коде) происходит.
Дружеский совет: почитай книжки (акцентируй внимание на работе с памятью и с ошибками). 

Спасибо за критику. Я действительно с Native и API столкнулся недавно, поэтому такой сумбур, но я учусь, а это немаловажно. поэтому и задаю вопросы, чтобы объяснили, а не отсылали к книжкам.
А теперь по существу.
Цитата
1. Для чего в данной строчке определяется Status ?
2. С чего ты взял, что если NtQueryValueKey отработает с ошибкой, то будет произведена запись
    в DataSize (которая, меду прочим, не инициализирована, но это "к слову") ?

Он, Status, в этой строке впринципе и не нужен, просто copy/paste. Функция действительно отрабатывает с ошибкой, но размер структуры в DataSize выдает, проверено. Не инициализирована переменная, потому что это просто наброск, черновик.
Цитата
3. Зачем вообще ты пытался получить  DataSize, если после этого выделяешь память
    таким образом data:=AllocMem(sizeof(KEY_VALUE_PARTIAL_INFORMATION)); ?
4. Почему в память размера sizeof(KEY_VALUE_PARTIAL_INFORMATION)
    ты пишешь DataSize байт, а потом еще удивляешся на AV ?
5. Где освобождение памяти ?

После долго перелопачивания MSDN и кучи кода на С, просто запутался. Но Я с этим разобрался, код переписал, см. ниже.
Цитата
6. Почему не используются try/finally ?

Я говорил, это только черновик.
А теперь далее.
Немного подправил код:
Описание структуры, которой нехватало в заголовочном файле, взял из MSDN, получилось вот так: 
Код

PKEY_VALUE_PARTIAL_INFORMATION=^KEY_VALUE_PARTIAL_INFORMATION;
  KEY_VALUE_PARTIAL_INFORMATION=packed record
    TitleIndex: ULONG;
    Type_: ULONG;
    DataLength: ULONG;
    Data:array[0..0] of UCHAR; 
  end;


Код

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
   _as:ANSI_STRING;
   us:UNICODE_STRING;
   KeyName: UNICODE_STRING;
   ValueName: UNICODE_STRING;
   SoftwareKeyHandle: THandle;
   Status: ULONG;
   ObjAttr: OBJECT_ATTRIBUTES;
   Key:widestring;
   Data:PKEY_VALUE_PARTIAL_INFORMATION;
   DataSize:ULONG;
begin
  Key:=sid;
  RtlInitUnicodeString(@KeyName,@key[1]);
  RtlInitUnicodeString(@ValueName,'Infium');
  InitializeObjectAttributes(@ObjAttr, @KeyName, OBJ_CASE_INSENSITIVE,0, nil);
  Status := NtOpenKey(@SoftwareKeyHandle,KEY_QUERY_VALUE,@ObjAttr);
  if not NT_SUCCESS(Status) then
   raise Exception.Create('Error: Couldn''t open registry tree')
   else
    begin
     NtQueryValueKey(SoftwareKeyHandle,@ValueName,KeyValuePartialInformation,nil,0,@DataSize);
     if DataSize <> 0 then
      begin
       Data := AllocMem(DataSize);
       GetMem(Data,DataSize);
       ZeroMemory(Data,DataSize);
      if Data <> nil then
       begin
        Status := NtQueryValueKey(SoftwareKeyHandle,@ValueName,KeyValuePartialInformation,Data, DataSize,@dataSize);
        if (NT_SUCCESS(Status)) and ( DataSize <> 0) then
         begin
          if Data^.Type_ = REG_SZ then
           begin
            RtlInitUnicodeString(@us, @data^.Data);
            Status:=RtlUnicodeStringToAnsiString(@_as,@us, true);
            if  NT_SUCCESS(status) then
              begin
                ShowMessage(_as.Buffer);
                RtlFreeAnsiString(@_as);
              end;
           end;
         end
      end
    end;
   end;
  NtClose(SoftwareKeyHandle );
  FreeMem(Data);


Все заработало, единственное, может какие будут замечания по поводу, кода.
Готов принять конструктивную критику.

Автор: Riply 31.10.2008, 18:14
Цитата(TeX @  31.10.2008,  09:01 Найти цитируемый пост)
но я учусь, а это немаловажно. поэтому и задаю вопросы, чтобы объяснили, а не отсылали к книжкам.


Мне казалось, что перед тем, как послать smile к книжкам,
я довольно подробно расписала ошибки, которые бросаются в глаза smile

Цитата(TeX @  31.10.2008,  09:01 Найти цитируемый пост)
Он, Status, в этой строке впринципе и не нужен, просто copy/paste


Еще как нужен smile
Более того, все дальнейшие шаги по чтению возможны только при
определенных его значениях (см MSDN) и они (шаги) зависят от этого значения.
(Например нет такого ValueName)

Цитата(TeX @  31.10.2008,  09:01 Найти цитируемый пост)
но размер структуры в DataSize выдает, проверено


То что десять раз выдало, вовсе не означает, что выдаст и на следующий.
Доказательством "выдавания" может служить только документация или исходный код
процедуры NtQueryValueKey

Цитата(TeX @  31.10.2008,  09:01 Найти цитируемый пост)
 Не инициализирована переменная, потому что это просто наброск, черновик.


Нет в программировании такого понятия как черновик. 
Или ты тестируешь один код (черновой),
оттестировал, а использовать будешь совсем другой (чистовой).
Зачем тогда было тестировать черновой вариант ? smile
Это раз.
Второе: 
ты привел код с просьбой найти ошибку. Я и ищу ошибку в приведенном коде,
а не телепатирую, что ты собираешся исправить в чистовом варианте smile

Теперь по коду:

Код

NtQueryValueKey(SoftwareKeyHandle,@ValueName,KeyValuePartialInformation,nil,0,@DataSize);
     if DataSize <> 0 then
      begin
       Data := AllocMem(DataSize);
       GetMem(Data,DataSize);


Я уж молчу про то что NtQueryValueKey может отработать с ошибкой
Следующие за ней две строчки показывают, что я не ошиблась отсылая тебя к книжкам:
ты действительно совершенно не понимаешь как работают с памятью.
Дальше смотреть не стала, ибо пока ты не прочитаешь книжку (на чем ставить акцент я уже говорила) дальнейшее обсуждение принципов работы Native-функций не имеет смысла.

 

Автор: TeX 1.11.2008, 16:24
Полностью соглашусь со всем вышенаписанным.
Тогда другой вопрос, какие книжки, по вашему мнению, стоит прочитать, чтоб разбираться, так же как и Вы ?
Цитата
   NtQueryValueKey(SoftwareKeyHandle,@ValueName,KeyValuePartialInformation,nil,0,@DataSize);
     if DataSize <> 0 then
      begin
       Data := AllocMem(DataSize);
       GetMem(Data,DataSize);
       ZeroMemory(Data,DataSize);
       if Data <> nil then

О ужас  smile , я только заметил это, какой непорядок, все это от перегрузки моска от такого количества инфы
Переделал так:
Код
 NtQueryValueKey(SoftwareKeyHandle,@ValueName,KeyValuePartialInformation,nil,0,@DataSize);
     if DataSize <> 0 then
      begin
       Data := AllocMem(DataSize);
       if Data <> nil then

Абосную выбор. AllocMem делает getMem и заполняет память нулями.

Автор: Riply 1.11.2008, 20:19
Цитата(TeX @  1.11.2008,  16:24 Найти цитируемый пост)
Тогда другой вопрос, какие книжки, по вашему мнению, стоит прочитать


Пройдись поиском по форуму.
Здесь не только давали голые ссылки на литературу, 
но и сопровождали их своими отзывами. 
IMHO - это помогает выбрать нужную исходя из своего уровня подготовки.
Я же конкретную книгу посоветовать не могу, т.к. не знаю этого уровня.
Но лично мне очень помог Рихтер. Он у меня и сейчас - "настольная книга"
в прямом и переносном смысле smile

По коду: настоятельно рекомендую не опираться на возвращаемое значение DataSize,
а анализировать код возврата  NtQueryValueKey (возможные коды должны быть в MSDN).
Насчет памяти, пока можно(нужно) и так. А когда научишся правильно обрабатывать
возвращаемое значение ф-ии, то затирание памяти станет избыточным
и его можно будет убрать.
Незачем загружать процессор излишней работой. Ему тоже отдохнуть хочется smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)