Вопрос по Delphi

Merlіn

dead wizard
Ответ: Помощь по Delphi

Выкладываю две статьи, воизбежание будущих вопросов полностью, про два способа работы в Delphi c реестром, первый с исп. WinAPI, второй с исп. модуля Registry, а там сам решай.
Доступ к реестру средствами API

Создать подраздел в реестре:
RegCreateKey (Key:HKey; SubKey: PChar; var Result: HKey): Longint;
Key - указывает на "корневой" раздел реестра, в Delphi1 доступен только один - HKEY_CLASSES_ROOT, а в Delphi3 - все.
SubKey - имя раздела - строится по принципу пути к файлу в DOS (пример subkey1\subkey2\ ...). Если такой раздел уже существует, то он открывается.
В любом случае при успешном вызове Result содержит Handle на раздел.
Об успешности вызова судят по возвращаемому значению, если ERROR_SUCCESS, то успешно, если иное - ошибка.

Открыть подраздел:
RegOpenKey(Key: HKey; SubKey: PChar; var Result: HKey): Longint;
Раздел Key
Подраздел SubKey
Возвращает Handle на подраздел в переменной Result. Если раздела с таким именем нет, то он не создается.
Возврат - код ошибки или ERROR_SUCCESS, если успешно.

Закрывает раздел:
RegCloseKey(Key: HKey): Longint;
Закрывает раздел, на который ссылается Key.
Возврат - код ошибки или ERROR_SUCCESS, если успешно.

Удалить подраздел:
RegDeleteKey(Key: HKey; SubKey: PChar): Longint;
Удалить подраздел Key\SubKey.
Возврат - код ошибки или ERROR_SUCCESS, если нет ошибок.

Получить имена всех подразделов раздела Key:
RegEnumKey(Key:HKey; index: Longint; Buffer: PChar; cb: Longint): Longint;
Key - Handle на открытый или созданный раздел
Buffer - указатель на буфер
cb - размер буфера
index - индекс, должен быть равен 0 при первом вызове RegEnumKey. Типичное использование - в цикле While, где index увеличивается до тех пор, пока очередной вызов RegEnumKey не завершится ошибкой

Возвращает текстовую строку, связанную с ключом Key\SubKey:
RegQueryValue(Key: HKey; SubKey: PChar; Value: PChar; var cb: Longint): Longint;
Ключ\подключ Key\SubKey.
Value - буфер для строки
cb - размер, на входе - размер буфера, на выходе - длина возвращаемой строки.
Возврат - код ошибки.

Задать новое значение ключу Key\SubKey:
RegSetValue(Key: HKey; SubKey: PChar; ValType: Longint; Value: PChar; cb: Longint): Longint;
Ключ\подключ Key\SubKey.
ValType - тип задаваемой переменной,
Value - буфер для переменной
cb - размер буфера. В Windows 3.1 допустимо только Value=REG_SZ.
Возврат - код ошибки или ERROR_SUCCESS, если нет ошибок.

Удаляет значение lpValueName находящееся в ключе hKey:
RegDeleteValue(HKEY hKey, LPCTSTR lpValueName);
hKey - ключ. hKey должен был быть открыт с доступом KEY_SET_VALUE процедурой RegOpenKey.
lpValueName - значение, находящееся в ключе hKey.
Возвращает ERROR_SUCCESS если успешно.

Выдает список значений у ключа hKey:
LONG RegEnumValue( HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcbValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);
hKey - ключ.
dwIndex - этот параметр должен быть 0 при первом вызове, а далее по анологии с RegEnumKey (т.е. можно использовать в цикле),
lpValueName - буфер для названия значения
lpcbValueName - размер lpValueName
lpReserved должно быть всегда 0
lpType - буфер для названия типа (int)
lpData - буфер для данных
lpcbData-размер для lpData
Примечание:
При каждой новом вызове функции после предыдущего нужно заново переназначить lpcbValueName.
lpcbValueName = sizeof(lpValueName)

Примеры:
{ Создаем список всех подразделов указанного раздела }
procedure TForm1.Button1Click(Sender: TObject);
var
MyKey: HKey; { Handle для работы с разделом }
Buffer: array[0 .. 1000] of char; { Буфер }
Err, { Код ошибки }
index: longint; { Индекс подраздела }
begin
Err := RegOpenKey(HKEY_CLASSES_ROOT, 'DelphiUnit', MyKey); { Открыли раздел }
if Err <> ERROR_SUCCESS then
begin
MessageDlg('Нет такого раздела !!', mtError, [mbOk], 0);
exit;
end;
index := 0;
{Определили имя первого подраздела }
Err := RegEnumKey(MyKey, index, Buffer, Sizeof(Buffer));
while err = ERROR_SUCCESS do { Цикл, пока есть подразделы }
begin
memo1.lines.add(StrPas(Buffer)); { Добавим имя подраздела в список }
inc(index); { Увеличим номер подраздела }
Err := RegEnumKey(MyKey, index, Buffer, Sizeof(Buffer)); { Запрос }
end;
RegCloseKey(MyKey); { Закрыли подраздел }
end;
Во второй статье вірезан пример (занимает много места).
Использование реестра
Реестр - это центральное хранилище информации о параметрах системы и установленных программах. В версиях Windows до Windows 95 программисты сохраняли параметры программ либо в INI-файлах WIN.INI и SYSTEM.INI, либо в дополнительных INI-файлах. Хотя использование INI-файлов поддерживается и в Win32, Microsoft настоятельно рекомендует для хранения необходимых в работе программы параметров пользоваться реестром. Реестр представляет собой иерархическую базу данных, cостоящую из секций, подсекций и элементов. Каждая секция имеет свое назначение. Хранить данные о пользовательских программах Microsoft рекомендует в секции HKEY_CURRENT_USER и подсекции Software. В этой подсекции вы создаете подсекцию, идентифицирующую вашу программу или фирму, и уже внутри нее располагаете данные.

Модуль Registry
Для упрощения работы с регистратором в состав Delphi (начиная с версии 2.0) входит модуль REGISTRY, содержащий реализацию трех классов, - TRegistry, TRegistryIniFile и TRegIniFile.
Внимание! Чтобы использовать свойства и методы классов TRegistry, TRegistryIniFile и TRegIniFile, необходимо включить в список uses модуль Registry.

TRegIniFile
Собственно говоря, задача класса TRegIniFile - упростить перенос 16-битных программ в среду Windows 95. Методы этого класса эквивалентны методам класса TIniFile в 16-битной версии Delphi. Класс TRegIniFile позволяет обращаться к секции HKEY_CURRENT_USER, считывать и записывать строки (методы ReadString и WriteString), целочисленные значения (методы ReadInteger и WriteInteger), логические значения (методы ReadBool и WriteBool), секции (методы ReadSection, ReadSections и ReadSectionValues), удалять секции (метод EraseSection) и элементы (метод DeleteKey). Рассмотрим на примерах, как используются функции этого класса.
Microsoft рекомендует записывать данные, относящиеся к вашей программе, в подсекции секции HKEY_CURRENT_USER_Software. Предположим (не особенно фантазируя на эту тему), что ваша программа называется RegDemo, и данные для нее располагаются в секции Software\RegDemo. Ниже мы покажем, как поместить в регистратор строчные, целочисленные и логические данные, а затем считать их, - этих операций будет достаточно для того, чтобы сохранить в регистраторе параметры нашей программы, а затем считать их.
Прежде чем записать данные в определенную секцию, ее необходимо создать. Это происходит при вызове конструктора объекта TRegIniFile. В качестве параметра вы указываете название секции, и если таковой не существует, она создается:

RegFile := TRegIniFile.Create(SubKey);

После того как файл регистратора открыт (и создана определенная секция), мы можем записать данные. Поддерживаются три типа данных: целочисленные, логические и строчные данные. Для записи этих данных существуют методы WriteInteger, WriteBool и WriteString. В качестве параметров указываются:
- название подсекции;
- название элемента;
- записываемые данные.
Так, чтобы записать значение элемента MyIntVal в подсекции IntKey, следует выполнить код

RegFile.WriteInteger(IntKey, 'Int_Val', 32000);

а для того чтобы прочесть значение, необходимо вызвать метод ReadInteger (в качестве параметров указываются название подсекции, название элемента и значение по умолчанию):

RegFile.ReadInteger(IntKey, 'Int_Val', 0));

Для чтения логических и строчных данных используются соответственно методы ReadBool и ReadStr, а для их записи – методы WriteBool и WriteString.
{Вырезанный пример}

Класс TRegistry

Прежде чем рассмотреть пример использования свойств и методов класса TRegistry, давайте кратко перечислим их.
В следующей таблице перечислены свойства класса TRegistry.
CurrentKey
Позволяет узнать текущую подсекцию, в которой проводятся операции по чтению и записи. Для изменения подсекции следует использовать методы OpenKey и OpenKeyReadOnly
CurrentPath
Позволяет узнать полное название текущей подсекции
LazyWrite
Задает способ обновления информации в реестре – непосредственно или после вызова метода CloseKey.
RootKey
Задает корневую секцию в реестре. По умолчанию установлено значение HKEY_CURRENT_USER

В следующей таблице перечислены методы класса TRegistry.

CloseKey
Записывает внесенные изменения и закрывает текущую подсекцию
Create
Создает экземпляр класса TRegistry и задает значение корневой секции - HKEY_CURRENT_USER
CreateKey
Создает подсекцию
DeleteKey
Удаляет подсекцию
DeleteValue
Удаляет значение элемента
Destroy
Уничтожает ранее созданный экземпляр класса TRegistry
GetDataInfo
Возвращает тип данных для указанного элемента
GetDataSize
Возвращает размер данных для указанного элемента
GetDataType
Возвращает тип данных для указанного элемента
GetKeyInfo
Возвращает информацию о текущем элементе
GetKeyNames
Возвращает имена подсекций для указанной секции
GetValueNames
Возвращает названия элементов для указанной подсекции
HasSubKeys
Позволяет узнать, имеются ли подсекции для указанной секции
KeyExists
Позволяет узнать, существует ли элемент
LoadKey
Создает новую подсекцию и загружает в нее информацию из указанного файла
MoveKey
Перемещает указанную подсекцию и все вложенные подсекции в заданное место
OpenKey
Открывает подсекцию
OpenKeyReadOnly
Открывает подсекцию только для чтения
ReadBinaryData
Считывает данные в бинарном формате
ReadBool
Считывает данные в булевом формате
ReadCurrency
Считывает данные в формате валюты
ReadDate
Считывает данные в формате даты
ReadDateTime
Считывает данные в формате “дата/время”
ReadFloat
Считывает данные в формате с плавающей точкой
ReadInteger
Считывает данные в целочисленном формате
ReadString
Считывает данные в строчном формате
ReadTime
Считывает данные в формате времени
RegistryConnect
Устанавливает соединение с реестром на другом компьютере
RenameValue
Переименовывает элемент
ReplaceKey
Замещает значение элемента значениями из файла
RestoreKey
Восстанавливает значение элемента из файла
SaveKey
Сохраняет значение элемента в файле
UnLoadKey
Удаляет подсекцию, загруженную методом LoadKey
ValueExists
Позволяет узнать, существует ли значение у элемента
WriteBinaryData
Записывает данные в бинарном формате
WriteBool
Записывает данные в булевом формате
WriteCurrency
Записывает данные в формате валюты
WriteDate
Записывает данные в формате даты
WriteDateTime
Записывает данные в формате “дата/время”
WriteExpandString
Записывает данные в формате "расширенно" строки
WriteFloat
Записывает данные в формате с плавающей точкой
WriteInteger
Записывает данные в целочисленном формате
WriteString
Записывает данные в строчном формате
WriteTime
Записывает данные в формате времени

После того как мы кратко познакомились со свойствами и методами класса TRegistry, давайте рассмотрим несколько примеров их использования.

Инициализация

Перед использованием свойств и методов класса TRegistry, необходимо создать экземпляр этого класса. Например:
var
R: TRegistry;
...R := TRegistry.Create;

Задание корневой секции

Если вы собираетесь работать с секцией, отличной от HKEY_CURRENT_USER (это значение задается по умолчанию), то после инициализации вы должны изменить значение свойства RootKey. Возможны следующие значения:

HKEY_CLASSES_ROOT
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_PERFORMANCE_DATA
HKEY_CURRENT_CONFIG
HKEY_DYN_DATA

Например:
with R do
begin
RootKey := HKEY_LOCAL_MACHINE;
//
// Продолжаем работу с реестром
//
end;
 

FafneR

Halt;
Ответ: Помощь по Delphi

Подскажите пожалуйста, каким образом можно предотвратить дублирование данных при вводе данных в таблицу.
Конкретный пример: в поле Name некоторой таблицы уже есть запись "Вася". Как сделать, чтобы когда пользователь пыталсяи ввести в таблицу ещё одного "Васю", приложение выдало бы, к примеру, сообщение о том, что такая запись уже существует и предложило бы альтернативу либо обновить старую запись, либо не вводить текущую.
Заранее благодарю.
 

Merlіn

dead wizard
Ответ: Помощь по Delphi

FafneR сказав(ла):
Подскажите пожалуйста, каким образом можно предотвратить дублирование данных при вводе данных в таблицу.
1. Если используеш БД и значение столбца уникально само выдаст ошибку нужно перехватить и обработать.
2. Если без БД перебрать все значения столбца на совпадение.
 
Ответ: Помощь по Delphi

Народ, кто подскажет?
Пишу прожку с использованием TServerSocket и TClientSocket. При подключении клиентской программы к серверной клиент сразу начинает передавать данные. Хочу, чтобы к серверу в каждый момент времени был подключен только 1 клиент. Но в TServerSocket не нашел ни свойств, ни методов, которые позволили бы ограничить число подключений. Другими словами, если к TServerSocket кто-то хочет подключиться, то он разрешает подключение всем (многопотоковый). Пробовал отключать клиента в серверной части по Socket.SocketHandle. Все бы отлично, но он успевает открыть канал данных для передачи и передаваемые данные "уходят в никуда", т.к. сервер их не принимает. Прием данных нужно организовать только от 1 клиента в каждый момент времени. Пробовал использовать обработчики событий OnGetSocket, OnGetThread, OnThreadStart (которые вызываются на этапе, когда клиент еще не подключился к серверу), но то ли я чего-то не понимаю, то ли эту цепочку вызова процедур для коннекта клиента к серверу нельзя нарушить (Access violation ...). Задача идеально бы решилась, если бы можно было бы запретить подключение новых клиентов на заданный порт, не обрывая при этом связи с 1 клиентом, который в данный момент осуществляет передачу данных, до момента его отключения.

P.S> Работать напрямую с сокетами слишком сложно. Поэтому за этот вариант не берусь, хотя и заню, что там это можно решить, переписав все под сокеты. Хочу использовать компоненты, облегчающие работу по созданию серверных приложений.
 

FEOFAN

http://feofan.com
Ответ: Помощь по Delphi

Ну я когда баловался с чатом Дельфи(сервер)+Флэш(как клиент) писал вот такую процедурку:
procedure TForm1.connect(Sender: TObject; Socket: TCustomWinSocket);
begin
inc(counter);
users.Caption:=inttostr(counter);
serversocket1.Socket.Connections[counter-1].SendText('Добро пожаловать!'+CHR(0));
end;
Очевидно ж это на коннект(просто давно это было). Очевидно ж на коннект, можно написать что-то роде этого(синтаксис примерный!!!):
procedure TForm1.connect(Sender: TObject; Socket: TCustomWinSocket);
begin
counter:=0;//это впиши де-нить на старте
inc(counter);
if counter=1 then StartToSendData() else
serversocket1.Socket.Connections[counter].Disconnect;//или какой-то другой метод, я не уверен что дисконнект
end;
//и не забыыть уменьшить число на дисконнект
procedure TForm1.disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
dec(counter);
end;
 
Останнє редагування:
Ответ: Помощь по Delphi

Да. В том-то и дело, что как сделать дисконнект клиенту я уже давно понял. Юзаю метод Socket.Disconnect(Socket.SocketHandle). Но клиент при коннекте к серверу начинает передавать инфу через SendText, на стороне сервера я то ReceiveText не вызываю для клиента, если к серверу уже подключен хотя бы 1 клиент. Основная проблема: хотя я на стороне сервера и не принимаю данные, они клиентом успевают передаться еще до того, как сервер отключит клиента. И данные уходят "в никуда". Идеальное решение данной ситуации: при коннекте клиента к серверу вызывается обработчик события OnGetSocket еще до установления коннекта. Если бы на этом этапе удалось как-то "вклиниться" в процесс вызова процедур и разрушить этот сокет, не вызвав при этом фатальных ошибок в приложении, это было бы решение этой проблемы. Пробовал методы Free, Destroy - Access violation ...
Close - "рубит" все подключения.

P.S> Интересный код получается для дисконнекта:
ServerSocket1.Socket.Connections[cur_connection].Disconnect(ServerSocket1.Socket.Connections[cur_connection].SocketHandle);
 
Останнє редагування:

FEOFAN

http://feofan.com
Ответ: Помощь по Delphi

Учимся читать мануал. 3 минуты поиска дали мне следующее:
PHP:
This example demonstrates how to add and delete menu items to a popup menu at runtime and assign an event handler to the OnClick event.

procedure TForm1.AddButtonClick(Sender: TObject);
var
  index: Integer;
  NewItem: TMenuItem;
begin
  for index := 0 to 3 do
  begin
    NewItem := TMenuItem.Create(PopupMenu1); // create the new item
    PopupMenu1.Items.Add(NewItem);// add it to the Popupmenu
    NewItem.Caption := 'Menu Item ' + IntToStr(index);
    NewItem.Tag := index;
    NewItem.OnClick = PopupMenuItemsClick;// assign it an event handler
  end;

end;

procedure TForm1.PopupMenuItemsClick(Sender: TObject);
begin
  with Sender as TMenuItem do
  begin
    case Tag of
      0:  ShowMessage('first item clicked');
      1:  ShowMessage('second item clicked');
      2:  ShowMessage('third item clicked');
      3:  ShowMessage('fourth item clicked');
    end;
  end;
end;

To edit or destroy an item, grab its pointer via the Items property.

procedure TForm1.EditButtonClick(Sender: TObject);
var
  ItemToEdit: TMenuItem;
begin
  ItemToEdit := PopupMenu.Items[1];
  ItemToEdit.Caption := 'Changed Caption';
}

procedure TForm1.DestroyButtonClick(Sender: TObject);
var
  ItemToDelete: TMenuItem;
begin
  ItemToDelete := PopupMenu.Items[2];
  ItemToDelete.Free;
end;
Еще 2 минуты и этот код работает с TMainMenu.
 

celeron

Забанен
Ответ: Помощь по Delphi

Народ, помогите хтото. Возможно хтото может помочь.(Заранее извиняюсь за повтор). Мне нужна такая программа, которая прописала бы мне и в блокнотик, или просто сгенерировала, что бы я смог скопировать и вставить, где мне нужно. Вот. Пример
10.0.0.1
10.0.0.2
10.0.1.3
10.0.1.4
10.0.1.5
10.0.1.6
10.0.1.7
10.0.1.8
10.0.1.9
...
10.0.200.256
Вот.Пожалуйста помогите. долго ето все прописівать вручную.
 

FEOFAN

http://feofan.com
Ответ: Помощь по Delphi

a:=1;
b:=1;
str="10.0.";
assignfile(f,"ip.txt");//точно не помню имя этой ф-ции
reset(f);
for a:=0 to 200 do begin
for b:=1 to 256 do begin
to_file:=str+inttostr(a)+"."+inttostr(b);
writeln(f,to_file);
end;
end;
closefile(f);
 
Зверху