Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "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.041 c
14-1130804324
Таблоид
2005-11-01 03:18
2005.11.20
Какие есть интересные англоязычные сайты по Delphi ?


14-1130464155
Idx
2005-10-28 05:49
2005.11.20
Где взять компонент для просмотра рисунков


14-1130409549
Антоний
2005-10-27 14:39
2005.11.20
Вопрос про контроль трафика с сервера Win2003Server


3-1128601467
Shc
2005-10-06 16:24
2005.11.20
Прорисовка DBRichEdit на DBCtrlGrid


2-1130837000
Dush
2005-11-01 12:23
2005.11.20
рисование на StringGrid





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский