500+ FAQ по Delphi

Перейти на: Главную | Индексную | Предыдущую | Следующую страницу
Сценарии Рубиновой свадьбы.

Чeм pабота чepeз FIBC лyчшe, чeм чepeз BDE?

1. Можно самостоятeльно выставлять паpамeтpы тpанзакций, дажe в runtime.
2. Можно выполнять тpанзакции на нeскольких базах данных.
3. Можно создавать "живые" запросы сразу к нескольким таблицам.
4. Пpиложeниe, использyющee FIBC нe нyждаeтся в поддepжкe BDE, eго пpощe
yстанавливать и настpаивать.
5. Пpи использовании FIBC появляeтся возможность пользоваться pолями
Interbase.

Могy ли я использовать FIBC для pаботы с C++ Builder?

Из-за pазличий в VCL подключить FIBC к С++ Builder 1.0 пpактичeски
нeвозможно. Под C++ Builder 3.0 FIBC встают бeз пpоблeм. Для этого нeобходимо
выбpать пyнкт Component/Install new component, в полe Unit file name yказать
файл FIBDataset.pas с пyтeм, нажать Ok. Затeм надо подключить в пpоeкт
gds32.lib и выполнить компиляцию. Далee чepeз Component/Install packages
добавить package с FIBC, и всe, библиотeкой можно пользоваться.

Установил Delphi, FIBC. Почeмy нe yдаeтся подключиться к yдалeнномy сepвepy?

FIBC тpeбyeт наличия yстановлeнного клиeнта Interbase.

Почему после выполнения FIBTransaction.Commit закpываются всe датасeты?

Для чeловeка, избалованного peжимом AUTOCOMMIT в BDE можeт показаться
нeпpивычным и нeyдобным то обстоятeльство, что пpи закpытии тpанзакции
автоматичeски закpываются всe датасeты. Пpичина такого повeдeния
заключаeтся нe в FIBC, а в Interbase. Дeло в том, что всe опepации в
Interbase выполняются только в контeкстe тpанзакции. Слeдоватeльно,
пpогpаммист сам должeн позаботиться об пepeоткpытии датасeтов и
восстановлeнии тeкyщих yказатeлeй послe Commit/Rollback. Peкомeндyeм
пользоваться мeтодом TFIBTransaction.CommitRetaining, котоpый выполняeт
Commit бeз закpытия кypсоpов (стандаpтная возможность Interbase).

Каким образом организовать подключение к базе данных с умолчательным паролем и именем пользователя?

1. Это можно сделать, например, так:
with FIBDatabase do begin
DBParams.Clear;
DBParams.Add('isc_dpb_user_name=SYSDBA');
DBParams.Add('isc_dpb_password=masterkey');
UseLoginPrompt:=false;
Connected:=true;
end;
2.Или так:
Используя переменные окружения :
в Autoexec.bat
SET ISC_USER=SYSDBA
SET ISC_PASSWORD=MASTERKEY
но в TFIBDatabase.DBParams все равно требуется прописать хотя бы,например
lc_ctype=win1251.Еще одна фича(или баг: ))
Префикс isc_dpb_ у опций, прописываемых в DBParams, можно опускать.

He yдаeтся ввeсти киpилличeскиe символы в таблицy.

Во-первых, yбeдитeсь, что база данных создана с кодовой страницей
win1251. Во-вторых, пропишитe в свойство DBParams у экзeмпляpа объeкта
TFIBDatabase строку isc_dpb_lc_ctype=WIN1251. Пpeфикс isc_dpb_ можно
опyскать.

Пpи конкypeнтном измeнeнии записи пpогpамма зависла. Почeмy? He вижy измeнeний данных на сepвepe, покyда нe выполню пepeзапyск тpанзакции. Почeмy?

Потомy что таковы yстановки паpамeтpов тpанзакции по yмолчанию.
В пepвом слyчаe ожидаeтся, когда бyдeт завepшeна конкypeнтная тpанзакция,
стаpтовавшая pаньшe (peжим wait), а во втоpом слyчаe пpичина - peжим
no_rec_version запyска тpанзакции. Побоpоть вышeозначeнныe пpоблeмы можно,
напpимep, пpописав в свойство TRParams y экзeмпляpа объeкта TFIBTransaction
слeдyющиe паpамeтpы:
isc_tpb_write
isc_tpb_nowait
isc_tpb_read_committed
isc_tpb_rec_version

префикс isc_tpb_ можно также опускать.
Hастоятeльно peкомeндyeм почитать о паpамeтpах тpанзакций в Interbase
API Guide (стp. 46 книги из состава Interbase Mediakit).

При вызове FIBDataSet.Open периодически возникает ошибка в строке pbd^[i] := nil метода FetchCurrentRecordToBuffer.

Смeнитe вepсию FIBC на болee свeжyю или заблокиpyйтe yчасток кода,
на котоpом возникаeт ошибка пyстым обpаботчиком ошибок.

Kак pаботать с blob сpeдствами FIBC?

Пpиводим пpимepы pаботы с blob-полями. FIBDatase1BLOBFIELD - полe
типа BLOB датасeта FIBDatabase1

Чтение из блоб-поля в OleContainer

var S: TStream;
begin
if not FIBDataset1BLOBFIELD.IsNull then
begin
S:=FIBDataset1.CreateBlobStream(FIBDataset1BLOBFIELD, bmRead);
try
OleContainer1.LoadFromStream(S)
finally
S.Free
end;
end;
end;

Запись в блоб-полe из OleContainer (вызываeтся в BeforePost)

var S: TStream;
begin
S:=FIBDataSet1.CreateBlobStream(FIBDataSet1BLOBFIELD, bmReadWrite);
try
OleContainer1.SaveToStream(S)
finally
S.Free
end;
end;

Как работать с новыми, своими интерфейсами в RemoteDataModule?

В редакторе библиотеки типов (typelib) Вы можете добавить свои интерфейсы и сделать их членами оригинального coClass. После этого Вы можете обращаться к этим интерфейсам, используя следующий синтаксис:

(IDispatch(RemoteServer.AppServer) as IAnother)

Необходимо заметить, что это будет работать только, если Вы используете DCOM как транспорт.

Как можно использовать TClientDataSet в локальном приложении с таблицами Paradox, без использования компонент TProvider и TRemoteServer?

Вы не сможете отделаться от Провайдера (хотя бросать его на форму/модуль данных не придется), но Вы сможете использовать TClientDataSet в одно-точечном (single-tier) приложении. Для того, чтобы открыть Client DataSet, Вы должны назначить Провайдера Данных вручную.

{ CDS = TClientDataSet }
{ Table1 = TTable }
CDS.Provider := Table1.Provider;
CDS.Open;

Также Вы должны включить модуль BDEProv в предложение Uses.

Как передать UserName и Password в удаленный модуль данных (remote datamodule)?

В Удаленный Модуль Данных бросьте компонент TDatabase, затем добавьте процедуру автоматизации (пункт главного меню Edit | Add To Interface) для Login.

Убедитесь, что свойство HandleShared компонента TDatabase установлено в True.

procedure Login(UserName, Password: WideString);
begin
{ DB = TDatabase }

{ Something unique between clients }
DB.DatabaseName := UserName + 'DB';
DB.Params.Values['USER NAME'] := UserName;
DB.Params.Values['PASSWORD'] := Password;
DB.Open;
end;

После того, как Вы создали этот метод автоматизации, Вы можете вызывать его с помощью:

RemoteServer1.AppServer.Login('USERNAME','PASSWORD');

Как я могу определить доступные сервера приложений на этой машине через Registry?

Прочитайте ключ под HKEY_CLASSES_ROOT\CLSID\*, просматривая его насчёт ключей, которые имеют подключ "Borland DataBroker". Эти вхождения и являются серверами приложений.

Ниже пример, который загружает имена доступных серверов приложений в Listbox:

uses Registry;
procedure TForm1.FormCreate(Sender: TObject);

var

I: integer;
TempList: TStringList;
begin
TempList := TStringList.Create;
try
with TRegistry.Create do
try
RootKey := HKEY_CLASSES_ROOT;
if OpenKey('CLSID', False) then
GetKeyNames(TempList);
CloseKey;
for I := 1 to TempList.Count - 1 do
if KeyExists('CLSID\' + TempList[I] + '\Borland DataBroker') then
begin
if OpenKey('CLSID\' + TempList[I] + '\ProgID', False)
then
begin
Listbox1.Items.Add(ReadString(''));
CloseKey;
end;
end;
finally
Free;
end;
finally
TempList.Free;
end;
end;

Я включил dbclient.dll в секцию "additional files" опций распространения по web, но этот файл никогда не загружается на клиента. Как это исправить?

Ваш INF-файл должен включать в себя строки наподобие:

[Add.Code]
dbclient.dll=dbclient.dll
[dbclient.dll]
file=http://yoursite.com/dbclient.cab
clsid={9E8D2F81-591C-11D0-BF52-0020AF32BD64}
RegisterServer=yes
FileVersion=4,0,0,36
Замените "yoursite" Вашим HTTP-адресом, где находится cab-файл.

FileVersion - это версия файла в Вашем cab-файле (проверьте информацию о версии DBCLIENT, чтобы быть уверенным в соответствии).

Убедитесь, что FileVersion относится к версии Вашего DBCLIENT.DLL.

Вы можете положить dbclient.dll в cab-файл, используя утилиту CABARC, которую Вы найдете в папке delphi\bin.

Примерная команда вызова CABARC может выглядеть примерно так:

CABARC N DBCLIENT.CAB DBCLIENT.DLL

Как достучаться до методов сервера приложений из TClientDataSet?

Вот так:

RemoteServer.AppServer.MyMethod.

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

Нужны ли мне формы в сервере приложений?

Да.

Необязательно, чтобы они были видимы, но должна присутствовать хотя бы одна. Чтобы сделать главную форму невидимой, установите

Application.ShowMainForm := False

в файле проекта.

Пример:

begin
Application.ShowMainForm := False;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Что я получаю от наличия ConstraintBroker (брокера ограничений)?

ConstraintBroker позволяет Вам включать проверки на ограничения в данные.

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

Поскольку это происходит без единой строчки кода, то Вам не требуется переписывать или обновлять приложение каждый раз при изменении правил.

Фактически это простое решение задачи обновления клиентского приложения без выхода из него.

Каждое приложение, использующее ConstraintBroker, автоматически получает это качество..

Предположим, что пользователь изменил строковое поле в Null. Как тогда я в обработчике OnUpdateData смогу определить, изменилось ли это поле на строку Null, или поле просто не было изменено?

Используйте свойство NewValue класса TField при чтении второй записи (той, которая содержит изменения). Если возвращаемое значение (variant) пусто или не назначено, тогда поле не было модифицировано.

Здесь немного иллюстрирующего кода:

var
NewVal: Variant;

begin
NewVal := DataSet.FieldByName('MyStrField').NewValue;
if VarIsEmpty(NewVal) then
ShowMessage('Field was not edited')
else if VarIsNull(NewVal) then
ShowMessage('Field was blanked out')
else
ShowMessage('New Field Value: ' + String(NewVal));
end;
Если Вы взглянете на исходники формы RecError (в репозитории), то Вы увидите, как она использует эту информацию для вывода строки '<Unchanged>' при показе ошибок синхронизации данных.

На сервере Вы добавляете ограничения уровня записи, используя свойство Constraints Вашего TQuery/TTable или ограничения уровня поля, используя постоянные обьекты TField (с помощью FieldsEditor либо на CustomConstraint, либо ImportedConstraint).

Если Вы используете ограничения уровня поля, они вступают в силу, когда данныеотправляются в поле (например, когда Вы уходите из органа управления, связанного с этим полем (типа TDBEdit)).

В чем разница между сокетами, DCOM и OLE Enterprise при использовании их в качестве транспорта?

Sockets (TCP/IP):
- на клиентах и сервере требуется наличие стека TCP/IP;
- не требуется дополнительной настройки клиентов;
DCOM:
- на клиентах и серверах требуется наличие DCOM (входит в состав Windows NT 4.0, для Windows 95 доступен как опция)
- требуется настройка клиентов (DCOM Configuration Utility - DCOMCNFG.EXE);
- встроенная поддержка модели безопасности Windows NT;
- поддержка обратных вызовов (методов);
CORBA
- на клиентах и серверах требуется наличие Common Object Request Broker;
- требуется настройка клиентов;
- поддержка обратных вызовов (методов);
OLE Enterprise:
- на клиентах и серверах требуется наличие OLE Enterprise;
- требуется настройка клиентов;
- поддержка обратных вызовов (методов).

Когда я применяю ApplyUpdates на ClientDataSet, на серверной стороне не срабатывает событие OnNewRecord для оригинального набора данных. Как это исправить?

Никак. Эти обновления идут прямо через BDE, а не через компонент набора данных.

----------------

В Delphi 4.0 (C++Builder 4.0) ситуация радикально изменилась.

Во-первых, обычному провайдеру данных (TProvider) можно указать, каким образом обновлять данные.

Во-вторых, новый тип провайдера (TDataSetProvider) работает только через соответвующие методы TDataSet.

То есть - все события при данных условиях на сервере будут отрабатываться обычным образом.

Если же Вы пользуетесь более старой версией Delphi, то, как обычно, можно посоветовать использование хранимых процедур, в данном контексте это будут методы сервера приложений. К сожалению, совет неприемлем для транспорта Sockets.

Как я могу выбрать на клиента только часть данных с определенной позиции из набора данных на сервере?

Наиболее приемлемым является использование TQuery и Provider.SetParams.

Но также Вы можете сделать это иначе:

Сперва на клиенте Вам нужно считать с сервера только метаданные для набора данных. Это можно сделать, установив PacketRecords в 0, и затем вызвав Open. Затем Вы должны вызвать метод сервера (Вы должны определить этот метод на сервере), который спозиционирует курсор на первую нужную запись.

И, наконец, установите PacketRecords в нужное значение, большее нуля, и вызовите GetNextPacket.

Почему мои ISAPI-ориентированные библиотеки, созданные в Delphi 3, не могут обрабатывать несколько соединений?

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

Это легко исправить, просто добавив строчку:

IsMultiThread := TRUE;

первой строкой в Вашем блоке begin-end файла проекта (DPR).

Как осуществить минимальный тест на корректность глобального идентификатора (GUID), и интерфейсов, унаследованных от IDispatch (и, следовательно, поддерживающих методы автоматизации)?

Вызовите CreateRemoteComObject, передав GUID интерфейса и имя компьютера, к которому Вы пытаетесь подключиться. Если функция вернет ошибку, то наличествует проблема сервера, иначе возможная проблема относится к клиенту.

const
MyGUID = '{444...111}'; //Whatever the guid is...

var
Unk: IUnknown;
Disp: IDispatch;

begin

{ Make sure this line works correctly }
Unk := CreateRemoteComObject('server1',
StringToGUID(MyGUID));

{ If it does, then cast it to a IDispatch }
Disp := Unk as IDispatch;

end;
Если этот кусок кода работает, а проблема остается, то Вам требуется шаг за шагом пройти через код клиента и найти, где он дает трещину. Если не сможете этого обнаружить, Вам придется запустить сервер под отладчиком и установить связь с клиентом, чтобы Вы могли произвести отладку рядом со местом, дающем слабину.

Как я могу избавиться от "зарегистрированного" имени сервера, если я не хочу использовать его далее?

Запустите исполняемый файл сервера с ключом /UNREGSERVER:

MYSERVER.EXE /UNREGSERVER

Это обычный путь разрегистрации саморегистрирующегося сервера автоматизации OLE.

После того, как я использовал правый щелчок мыши для создания функции-провайдера, как мне снова выполнить команду контекстного меню "Export from Table"?

Как только Вы экспортировали интерфейс провайдера, эта команда контекстного меню перестает быть видимой. Чтобы снова включить ее, Вы должны удалить ассоциированное свойство в Редакторе Библиотеки Типов, и затем нажать кнопку обновления информации в Редакторе Библиотеки Типов (Type Library Editor's Refresh button).

Вы могли бы также удалить точку вхождения "Get_XXX" в исходном тексте RemoteDataModule.

Что такое LZCopy?

Вот простой пример копирования файла (сжатого или нет):

----------
Var
srcHandle, destHandle: Integer;
srcBuf, destBuf: TOFStruct;

srcHandle := LZOpenFile( f_source, srcBuf,
OF_READ or OF_SHARE_DENY_NONE );
If srcHandle = -1 Then
CopyFailed
Else Begin
destHandle := LZOpenFile( f_target, destBuf,
OF_CREATE or OF_SHARE_EXCLUSIVE );
If destHandle = -1 Then
CopyFailed
Else Begin
If LZCopy( srcHandle, destHandle ) < 0 Then
CopyFailed;
LZClose( destHandle );
End; { Else }
LZClose( srcHandle );
End; { Else }

f_source и f_target - указатели на терминированные нулем строки (PChars) с именем исходного и целевого файла. CopyFailed - просто процедура для вывода сообщения об ошибке, создайте ее сами.

Если вам необходимо скопировать сразу несколько файлов, эффективнее использовать последовательность:

------------

LZStart;
For i:=1 to numSourcefiles Do Begin
scrHandle := _lopen( имя исходного файла ... );
targetHandle := _lcreat( имя целевого файла... );
CopyLZFile( scrHandle, targetHandle );
_lclose( srcHandle );
_lclose( targetHandle );
End;
LZDone;
(* добавьте проверку на ошибку в каждом шаге! *)

Все имена файлов должны терминироваться нулем, не используйте паскалевские строки! Самый простой путь для добавления нуля в конец строки - добавление символа #0 и передача адреса первого символа строки, например (@str[1]).

---------------

Var
source: string;
sourceHandle: Word;


....
source:= 'a:\anyfile.ext';
....
source := source+#0;
sourceHandle := _lopen( @source[1], READ or OF_SHARE_DENY_NONE );

Изменение расширения BITMAP???


Я изменил расширение изображения с BMP на 3LG. Затем для загрузки *.3LG-файла в виде изображения в компонент Image1 я даю команду
Image1.Picture.LoadFromFile('C:\TEST.3LG');
я получаю ошибку, говорящую о неверном расширении. Как мне обойти это? (это тот же BMP, но я просто изменил ему расширение)

Смотри процедуру RegisterFileFormat.


Материалы находятся на сайте http://cracklab.narod.ru/faq/


Создатель этого HTML файла не претендует на авторство вопросов/ответов представленных в нём, не отвечает за их содержание и достоверность, а также за последствия использования программных кодов , полученных из этого HTML файла. Также не принимаются претензии относительно не размещённой информации об авторе каждого конкретного FAQ'а. Любые другие вопросы присылайте на bad_guy@cracklab.ru (обращаться к Bad_guy'ю).
Hosted by uCoz