![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
DCOM. Ошибка: Интерфейс не поддерживается. [Delphi, Windows]
Артем Кудлаекно © (2005-10-18 12:59:00)
library CalcSubscription;
uses
ComServ,
ComObj,
MyCalc_TLB in 'MyCalc_TLB.pas',
Unit1 in 'Unit1.pas' {Calc: CoClass};
exports
DllGetClassObject,
DllCanUnloadNow,
DllRegisterServer,
DllUnregisterServer;
{$R *.TLB}
{$R *.RES}
begin
end.
unit MyCalc_TLB;
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
interface
uses Windows, ActiveX, Classes, Graphics, StdVCL, Variants;
const
MyCalcMajorVersion = 1;
MyCalcMinorVersion = 0;
LIBID_MyCalc: TGUID = '{6C701D29-BF27-4B10-9139-B94F410CB5C2}';
IID_ICalc: TGUID = '{FD810922-1BDB-48D1-93D3-65E584854C6E}';
CLASS_Calc: TGUID = '{9D5C87A5-8BE2-40D8-B4C0-391D201F9B87}';
type
ICalc = interface;
Calc = ICalc;
ICalc = interface(IUnknown)
['{FD810922-1BDB-48D1-93D3-65E584854C6E}']
function DoSomethind(as_text: OleVariant): HResult; stdcall;
end;
CoCalc = class
class function Create: ICalc;
class function CreateRemote(const MachineName: string): ICalc;
end;
implementation
uses ComObj;
class function CoCalc.Create: ICalc;
begin
Result := CreateComObject(CLASS_Calc) as ICalc;
end;
class function CoCalc.CreateRemote(const MachineName: string): ICalc;
begin
Result := CreateRemoteComObject(MachineName, CLASS_Calc) as ICalc;
end;
end.
unit Unit1;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
Windows, ActiveX, Classes, ComObj, MyCalc_TLB, StdVcl, Dialogs;
type
TCalc = class(TTypedComObject, ICalc)
protected
function DoSomethind(as_text: OleVariant): HResult; stdcall;
{Declare ICalc methods here}
end;
implementation
uses ComServ;
function TCalc.DoSomethind(as_text: OleVariant): HResult;
begin
ShowMessage(as_text);
Result := S_OK;
end;
initialization
TTypedComObjectFactory.Create(ComServer, TCalc, Class_Calc,
ciMultiInstance, tmApartment);
end.
Код в приложении рабочий:
procedure TForm1.Button2Click(Sender: TObject);
var Calc:ICalc;
begin
Calc := CoCalc.Create;
Calc.DoSomethind('Test');
end;
Код в приложении не рабочий:
procedure TForm1.Button3Click(Sender: TObject);
var Calc:ICalc;
begin
Calc := CoCalc.CreateRemote('localhost');
Calc.DoSomethind('Remote is good!');
end;
CalcSubscription.dll скопировал в C:\Windows\System32.
Вызвал regsvr32 CalcSubscription.dll.
При вызове CreateRemote('localhost') в процессах появляется dllhost.
В dcomcnfg нашел свой GUID и дал всем все права.
Что я еще не сделал?
Набережных С. (2005-10-19 17:50:00) [1]Дельфи умеет работать только с SafeArray of integer. И, кстати, в большинстве случаев удобнее иметь дело с OleVariant, чем напрямую с pSafeArray.
Для передачи массива записей существует несколько способов - через VarArrayCreate etc, через интерфейс-перечислитель, через объект, маршалируемый по значению. выбор зависит от условий задачи и от типов данных в записи.
ЗЫ Вопрос вышел за тему этой ветки, а в таких случаях принято создавать новые ветки.
Артем Кудлаенко (2005-10-19 15:41:00) [2]Прочитал в справке, что массивы должны передавать через специальный тип называемый SafeArray. Я выбераю этот тип через окно мастера Type Library (SAFEARRAY(long))и у меня в параметр метода подставляется тип PSafeArray без указания типа(of long).
Как работать с массивами(двухмерными тоже)? Тип элементов я должен указать в скобках? На пример: SAFEARRAY(double)
Так же в справке написано(если я правльно понял), что в *_TLB модуле не отображается тип элементов.
Набережных С. (2005-10-19 12:04:00) [3]
> isasa © (18.10.05 21:58) [9]
> 3. Proxy-часть маршалинга встроена в сервер.
Ну откуда такие фантазии?:( Я ж сказал - OleAut32...
> Артем Кудлаенко © (18.10.05 21:02) [8]
> 4. Почему сервер выполнял недопустимую операцию, пока я
> не сменил учетную запись с которой запускается сервер с
> "Запускающего пользователя" на "Текущего пользователя"?
Универсальному маршалеру на клиенте для правильной организации маршилинга вызовов требуется информация о типах параметров методов и о способе их передачи. Такая информация находится в библиотеке типов сервера и именно эта библиотека и необходима на клиенте. Когда ты на клиенте зарегистрировал сервер, то он автоматически зарегистрировал и свою библиотеку типов, поэтому и заработало. Хотя на клиенте регистрировать сервер нет необходимости, достаточно скопировать туда и зарегистрировать файл *.TLB.
> 4. Почему сервер выполнял недопустимую операцию, пока я
> не сменил учетную запись с которой запускается сервер с
> "Запускающего пользователя" на "Текущего пользователя"?
Вероятно, на компьютере сервера у клиента нет прав. Нужно дать права учетке клиента на сервере. Но лучше все-же установить запуск сервера от конкретной специально созданной учетной записи или от LocalSystem. Почему долго объяснять, а у меиня нет времени, поищи в инете есть.
> 5. Когда я проверял эмпирическим путем какие права нужны
> для того, чтобы клиенты могли вызывать сервер, я запретил
> доступ всем. Теперь из dcomcnfg пропал мой сервер и я не
> могу вернуть все обратно. В реестре, естественно, не могу
> удалить все ветки с моим GUID`ом. Как можно вернуть все
> "на родину"?
Попробуй войти в систему как админ, запусти regedt32, сделай себя владельцем и дай себе все права на эти ветки реестра. Должно помочь.
isasa (2005-10-18 22:33:00) [4]WideString в *_TLB.pas - нормально.
См. View -> Type library -> тыкни на методе -> см. закладку Text
Артем Кудлаенко (2005-10-18 22:14:00) [5]
> TCalc = class(TAutoObject, ICalc) ????
TCalc = class(TTypedComObject, ICalc)
И сейчас(после того как перевел сервер на исполняемый) в параметре метода тип не OleVariant, а WideString(Я все делал с помощью мастера и выбрал для метода тип BSTR)
isasa (2005-10-18 21:58:00) [6]Если без глубокой теории:
1. Да (в разных адресных пространствах)
2. Да. (поэтому этого лучше не делать). Если сильно приспичит передать, что-нибудь не OLE, например, record, пакуй ее в VarArray.
3. Proxy-часть маршалинга встроена в сервер.
4. Не знаю.
5. Попробуй вернуть права через Владелец (Кнопка Дополнительно).
Еще, мастер прототипом ставит(в D7) TAutoObject
TCalc = class(TAutoObject, ICalc) ????
Артем Кудлаенко (2005-10-18 21:02:00) [7]Спасибо за разъяснения.
На данный момент меня proxy/stub пугает. И путаюсь немного тоже :)
Я сделал сервер в виде исполняемого файла. Все заработало.
1. Сейчас, когда все работает, используется универсальный маршалер?
2. Если я правильно понял, когда я буду использовать в параметрах методов типы не совместимые с OleAutomation, то мне прийдется писать свой proxy/stub?
3. Почему возникала ошибка "Interface not supported" пока я не зарегистрировал сервер на машине клиента?
4. Почему сервер выполнял недопустимую операцию, пока я не сменил учетную запись с которой запускается сервер с "Запускающего пользователя" на "Текущего пользователя"?
5. Когда я проверял эмпирическим путем какие права нужны для того, чтобы клиенты могли вызывать сервер, я запретил доступ всем. Теперь из dcomcnfg пропал мой сервер и я не могу вернуть все обратно. В реестре, естественно, не могу удалить всеветки с моим GUID`ом. Как можно вернуть все "на родину"?
Набережных С. (2005-10-18 18:43:00) [8]И еще, разумеется, не придется писать Proxy/Stub для тех интерфейсов, для которых proxy/stub уже кем-то написаны и имеются в системе, например большинство определенных в системе интерфейсов - ну это, думаю, вполне очевидно.
Набережных С. (2005-10-18 18:35:00) [9]
> isasa © (18.10.05 17:43) [5]
> Не надо пугать человека.
Да, не придется - если будет использован универсальный маршалер из Oleaut32, как уже было сказано выше. Сам факт размещения сервера в exe-файле вовсе этого не гарантирует. В exe-сервере прекрасным образом могут располагаться объекты, реализующие не совместимые с оле интерфейсы, либо эти интерфейсы могут быть не помечены как OleAutomation, либо для них может не быть библиотеки типов - все эти варианты вполне допустимые, но только тогда потребуется иметь proxy/stub для каждого из реализованных в сервере интерфейсов, с которым предполагается работа клиентов.
Так что не надо путатьчеловека.
isasa (2005-10-18 17:43:00) [10]Не надо пугать человека.
Естественно маршаллинг(proxy/stub) будет.
Но писать самому его не придется.
Набережных С. (2005-10-18 17:18:00) [11]>Артем Кудлаенко © (18.10.05 14:19) [2]
>Получается, мне необходимо реализовать еще одну DLL: proxy/stub?
Не обязательно. В данном случае
ICalc = interface(IUnknown)
['{FD810922-1BDB-48D1-93D3-65E584854C6E}']
function DoSomethind(as_text: OleVariant): HResult; stdcall;
end;
в качестве proxy/stub может быть использован универсальный маршалер из oleaut32.dll, так как в методе интерфейса все параметры OleAutomation - совместимые.
>Я могу этого всего избежать, если сервер будет реализован в виде исполняемого файла?
Нет, proxy/stub необходимы. proxy/stub служат как раз для упаковки/распаковки параметров вызовов в вид, пригодный для передачи между процессами и машинами. Если клиент и сервер находятся в разных процессах, то пара proxy/stub необходима.
isasa (2005-10-18 14:50:00) [12]По идее, да.
CLSCTX_REMOTE_SERVER = 16 (*.exe)
Артем Кудлаенко (2005-10-18 14:19:00) [13]Получается, мне необходимо реализовать еще одну DLL: proxy/stub?
Я могу этого всего избежать, если сервер будет реализован в виде исполняемого файла?
isasa (2005-10-18 13:26:00) [14]У DLL нет своего адресного пространства, поэтому она просто так DCOM не будет.
См. MSDN, ключевые слова Surrogate Sharing, DllSurrogate