Форум: "Corba";
Текущий архив: 2005.11.20;
Скачать: [xml.tar.bz2];
ВнизCOM Server&Client (почти по Тенцеру) Найти похожие ветки
← →
Сергей Александров (2005-02-07 04:56) [0]1) Приложение-сервер (EXE).
Имеется интерфейс (файл Intf.pas):
type
ITest = interface (IUnknown)
["{6847A0CC-1EDA-4AD1-9B80-A42A06412D7D}"]
procedure A; stdcall;
end;
Определена константа:
const
Class_Test: TGUID = "{A266C4D4-B1F4-4439-B024-BA73E33F7E87}";
Реализуется и регистрируется (файл SrvSrc.pas):unit SrvSrc;
interface
uses Windows, ActiveX, Classes, ComObj, Intf;
type
TTest = class (TComObject, ITest)
protected
procedure A; stdcall;
end;
implementation
uses ComServ;
{ TTest }
procedure TTest.A;
begin
Beep
end;
initialization
CoInitialize(nil);
TComObjectFactory.Create(ComServer, TTest, Class_Test,
"Test", "", ciMultiInstance, tmSingle);
end.
2) Приложение-клиент.
в uses добавлен файл с объявлением интерфеса:uses Intf.pas
По клику на кнопке выполняется следующий код:procedure TForm2.Button1Click(Sender: TObject);
var
ATest: ITest;
begin
ATest := CreateComObject(Class_Test) as ITest; // ?
end;
В результате: сервер запускается, клиент выдает ошибку: Interface not supported.
Примечание: ссылку наIUnknown
выдает прекрасно.
Ткните носом, пожалуйста в незнание очевидных вещей. Вроде почти Copy/Paste из Тенцера, а не пашет, хоть убей. Помогите разобраться.
← →
Набережных С. © (2005-02-07 07:59) [1]>ITest = interface (IUnknown)
Такому интерфейсу для межапартаментного взаимодействия нужна прокси/стаб длл. В поставке Delphi поддержки этого нет. Либо писать самому, либо использовать IMarshal, что ничуть не проще. Наследуй интерфейс от IDispatch, включи в проект библиотеку типов и все заработает.
← →
Сергей Александров (2005-02-07 09:45) [2]Спасибо за доступное объяснение, сдвинулся с мертвой точки.
:)
← →
Григорьев Антон © (2005-02-07 11:28) [3]Наследовать от IDispatch в данном случае не обязательно. Просто нужно изначально делать COM-объект с библиотекой типов. Проще всего для этого воспользоваться мастером создания COM-объекта в диалоговом окне File/New/Other... на странице ActiveX. Если там не убирать галочки, стоящие по умолчанию, то будет создан COM-объект с фабрикой класса и с библиотекой типов, поддерживающих универсальный маршалинг, унаследованные от TTypedComObject и TTypedComObjectFactory соответственно. Для создания библиотеки типов откроется специальное окно - там всё очевидно, сами сможете разобраться, что к чему. Созданная библиотека типов будет автоматически помещена в exe-файл сервера и зарегистрирована при его запуске.
← →
Набережных С. © (2005-02-07 14:31) [4]>Григорьев Антон © (07.02.05 11:28) [3]
Вот только смысла в таких интерфейсах никакого нет - ограничения те же, что и у потомков IDispatch, а возможностей автоматизации нет. И забивать ими голову на начальном этапе освоение не нужно.
← →
Владислав © (2005-02-07 15:20) [5]> Набережных С. © (07.02.05 07:59) [1]
Ну вы не пугайте человека :)
Вот часть idl файла:
[
object,
uuid(FA307E85-5272-44d0-BDB2-F9433C8BAC8B),
helpstring("IServerConnector Interface"),
pointer_default(unique)
]
interface IServerConnector : IUnknown{
[helpstring("method GetServerList")] HRESULT GetServerList([out] IServerList ** ServerList);
};
// IServerList Interface
[
object,
uuid(297481F0-A3D2-43d1-B0DB-9A6C4B007885),
helpstring("IServerList Interface"),
pointer_default(unique)
]
interface IServerList : IUnknown{
[helpstring("method RegisterServer")] HRESULT RegisterServer([in] BSTR ConnStr, [out] LPDBOBJECTID ObjID, [out] IServer ** Server);
[helpstring("method UnregisterServer")] HRESULT UnregisterServer([in] LPDBOBJECTID ObjID);
[helpstring("method EnumServer")] HRESULT EnumServer([out] IEnumServer ** Enum);
};
// IServer Interface
[
object,
uuid(4F2431AA-1637-4d8c-B093-4E045E9D7AC0),
helpstring("IServer Interface"),
pointer_default(unique)
]
interface IServer : ICommonObject{
[helpstring("method Connect")] HRESULT Connect([in] BSTR ConnStr);
[helpstring("method Disconnect")] HRESULT Disconnect(void);
[helpstring("method GetConnectString")] HRESULT GetConnectString([out] BSTR * ConnStr);
[helpstring("method CreateDatabase")] HRESULT CreateDatabase([in] BSTR FileName, [out] LPDBOBJECTID ObjID, [out] IDatabase ** Database);
[helpstring("method DropDatabase")] HRESULT DropDatabase([in] LPDBOBJECTID ObjID);
[helpstring("method RegisterDatabase")] HRESULT RegisterDatabase([in] BSTR FileName, [out] LPDBOBJECTID ObjID, [out] IDatabase ** Database);
[helpstring("method UnregisterDatabase")] HRESULT UnregisterDatabase([in] LPDBOBJECTID ObjID);
[helpstring("method EnumDatabase")] HRESULT EnumDatabase([out] IEnumDatabase ** Enum);
};
// IEnumServer Interface
[
object,
uuid(D1019908-2CB3-4e71-9649-942750D0ED47),
helpstring("IEnumServer Interface"),
pointer_default(unique)
]
interface IEnumServer : IUnknown{
[helpstring("method Next")] HRESULT Next([in] ULONG celt, [out] IServer ** rgelt , [out] ULONG * pceltFetched);
[helpstring("method Skip")] HRESULT Skip([in] ULONG celt);
[helpstring("method Reset")] HRESULT Reset(void);
[helpstring("method Clone")] HRESULT Clone([out] IEnumServer ** ppenum);
};
// ICommonObject Interface (Base interface)
[
object,
uuid(03E64637-436F-459d-A13A-C767F56B5A4F),
helpstring("ICommonObject Interface"),
pointer_default(unique)
]
interface ICommonObject : IUnknown{
[helpstring("method GetObjectInfo")] HRESULT GetObjectInfo([out] LPDBOBJECTID id, [out] BSTR * Name, [out] BSTR * Description);
[helpstring("method SetObjectInfo")] HRESULT SetObjectInfo([in] BSTR Name, [in] BSTR Description);
};
Вот использование:procedure TForm1.Button1Click(Sender: TObject);
var
hr: HRESULT;
LCount: Cardinal;
LServConn: IServerConnector;
LServList: IServerList;
LEnumServ: IEnumServer;
LCommnObj: ICommonObject;
LServ: IServer;
begin
hr := CoCreateInstance(CLASS_ServerConnector, nil, CLSCTX_INPROC_SERVER,
IID_IServerConnector, LServConn);
if Succeeded(hr) then
begin
hr := LServConn.GetServerList(LServList);
if Succeeded(hr) then
begin
hr := LServList.EnumServer(LEnumServ);
if Succeeded(hr) then
begin
hr := LEnumServ.Next(1, LCommnObj, LCount);
while (hr <> S_FALSE) do
begin
LServ := IServer(LCommnObj);
hr := LEnumServ.Next(1, LCommnObj, LCount);
end
end
end
end
end;
Никаких специальных прокси/заглушек, никаких IDispatch.
Пример рабочий.
← →
Набережных С. © (2005-02-07 16:10) [6]>Владислав © (07.02.05 15:20) [5]
>hr := CoCreateInstance(CLASS_ServerConnector, nil, CLSCTX_INPROC_SERVER,
IID_IServerConnector, LServConn);
Вы о чем? Смысл выделенного параметра Вам понятен? А также смысл выражения "для межапартаментного взаимодействия"?
← →
Григорьев Антон © (2005-02-07 17:39) [7]
> Набережных С. © (07.02.05 14:31) [4]
> >Григорьев Антон © (07.02.05 11:28) [3]
>
> Вот только смысла в таких интерфейсах никакого нет - ограничения
> те же, что и у потомков IDispatch, а возможностей автоматизации
> нет. И забивать ими голову на начальном этапе освоение не
> нужно.
<offtopic>
Это смотря что считать начальным этапом. Если начинать изучение с того, куда щёлкнуть мышкой, чтобы всё работало - тогда, может, и так. А вот если последовательно разбираться с теорией, тогда всё-таки лучше сначала разобраться с интерфейсами и маршалингом вообще на примере custom-интерфейсов и лишь потом приступить к изучению интерфейсов диспетчеризации и дуальных интерфейсов.
</offtopic>
← →
Сергей Александров (2005-02-07 18:32) [8]Спасибо за обилие информации.
Не подскажите ли, каков оптимальный (общепринятый) порядок действий в следующей ситуации.
Имеется уже готовый проект, с развитой системой плагинов, реализованных через интерфейсы. То есть уже существует система интерфейсов, достаточно сложная. И захотелось все это дело (то есть готовые интерфейсные юниты) сделать доступными через COM (Для вызова из других приложений в видеCreateCOMObject(...)
). Неужели - единственный выход, это заново описывать эти интерфейсы в редакторе типов. Нельзя ли библиотеку типов сформировать для этих юнитов хотя-бы "полуавтоматически".
Вот, например, фрагмент интерфейса главного АПИ сервера:IXApplication = interface (IUnknown)
["{EC477519-755C-4DA2-9223-9BBA17A57DDF}"]
procedure Halt; stdcall;
function GetAPIVersion: TXAPIVersion;stdcall;
function GetMainWindow: IMainWindow;stdcall;
function GetCurrentDocumentWindow: IDocumentWindow;stdcall;
function GetCurrentReportWindow: IReportWindow;stdcall;
procedure ShowProgressIndicator (const ACaption: WideString);
procedure UpdateProgressIndicator (const Pos,MaxPos: Integer);
procedure HideProgressIndicator;
function CreateGeoCalculator (AType: Integer): IGeoCalculator;
function AppSettings: IApplicationSettings;
procedure Halt; stdcall;
...
end;
Нельзя ли для него typelibrary сформировать как-то "автоматически", или придется typelibrary переописывать самому.
Заранее благодарен за ответ.
← →
Набережных С. © (2005-02-07 19:20) [9]>Григорьев Антон © (07.02.05 17:39) [7]
>лучше сначала разобраться с интерфейсами и маршалингом вообще на примере custom-интерфейсов и лишь потом приступить к изучению интерфейсов диспетчеризации
Что-то я не уловил смысл этой фразы применительно к [3] и [4]. Можно разъяснить, что значит "маршалингом вообще на примере custom-интерфейсов" и почему "лишь потом приступить к изучению интерфейсов диспетчеризации и дуальных интерфейсов.
"? И как это соотносится с [3]? Очень хочется услышать.
А для стандартной работы с IDispatch вовсе не нужно знать тонкости дуализма и диспетчиризации, многие не знают и ничего, обходятся, благо Delphi это позволяет. Когда почувствует потребность, тогда и разберется.
>Сергей Александров (07.02.05 18:32) [8]
Придется вручную, по крайней мере мне такие конвертеры не известны. Но и это еще не все. Если у какого-то интерфейса хотя-бы в одном из методов есть параметр, не совместимый с OLE Automation, то Delphi не сможет тебе помочь в его маршалинге. В этом случае придется писать IDL файл и делать прокси/стаб в студии. Либо писать их для него вручную, однако это дело непростое. Ошибка была сделана на этапе проектирования - не тот базовый интерфейс выбран. И если завтра тебе скажут, что нужно подключаться к твоему серверу из клиента на бейсике или из скрипта, то придется полностью переписывать весь сервер.
← →
Сергей Александров (2005-02-07 23:24) [10]
> [9] Набережных С. © (07.02.05 19:20)
Спасибо за разъяснения. Буду копать, может часть интерфейса вытащить в КОМ все-же удастся, хотя-бы базовые функции. Еще раз спасибо.
← →
Григорьев Антон © (2005-02-08 16:03) [11]
> Набережных С. © (07.02.05 19:20) [9]
> А для стандартной работы с IDispatch вовсе не нужно знать
> тонкости дуализма и диспетчиризации, многие не знают и ничего,
> обходятся, благо Delphi это позволяет. Когда почувствует
> потребность, тогда и разберется.
Мне очень не нравится такой подход, потому что без знания теории постоянно лезут проблемы, стоит лишь чуть-чуть выйти за рамки тех возможностей, которые предусмотрели авторы VCL. Отсюда и утверждение о том, что сначала лучше разобраться с тем, как вообще это всё работает, а потом уже изучать IDispatch как частный случай использования интерфейсов.
← →
Набережных С. © (2005-02-08 16:44) [12]>Григорьев Антон © (08.02.05 16:03) [11]
Антон, мне тоже не очень. Вот перед нами пример, к чему это может привести. Но проблема-то в том, что делать надо сейчас, а не когда все доскально изучишь. Потому и говорю, что не надо отвлекаться на неавтоматизационные интерфейсы. Соглась, круг задач, где следует им отдать предпочтение, черезвычно ограничен. С другой стороны, стандартная работа с потомками IDispatch ничем не отличается от работы с такими интерфесами, так что никаких дополнительных навыков они не дадут. И еще одно НО. Delphi позволяет начать работу с интерфейсами, не имея о них глубоких знаний, она даже не требует от программиста знания IDL! А практика упрощает процесс понимания, что же это за зверь такой. И тогда уже будет проще идти дальше, вникая во все тонкости и разбираясь с возможностями. Проще уже будет понять саму сущность СОМ. Такое вот мое мнение. И извини за излишнюю резкость.
← →
Владислав © (2005-02-09 11:42) [13]> Набережных С. © (07.02.05 16:10) [6]
Мда... конечно знаю. Виноват. Это моя невнимательность.
← →
Григорьев Антон © (2005-02-09 14:33) [14]
> Набережных С. © (08.02.05 16:44) [12]
> И извини за излишнюю резкость.
Ничего страшного, я не обиделся. Согласен, что практика иногда заставляет что-то делать, не оставляя время на получение глубоких знаний. Просто мне сейчас приходится очень много думать вот об этом проекте: http://www.delphikingdom.com/lyceum/seminar.asp?partID=8 - вот и начал мыслить однобоко, с крутым креном в сторону теории :))
Страницы: 1 вся ветка
Форум: "Corba";
Текущий архив: 2005.11.20;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.046 c