ATL, .NET 2003
Правила форума
Пожалуйста, ознакомьтесь с правилами данного форума
Пожалуйста, ознакомьтесь с правилами данного форума
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
ATL, .NET 2003
При создании ATL проекта с именем xxx в том же солюшн генерируется проект с именем xxxPS (прокси стаб). Там лежит обычный *.def для COM и несколько *.с файлов. Не помню, но такого раньше не было в VC 6.0. Для чегой-то выделили в отдельный проджект всё это хозяйство?
Спасибо.
Спасибо.
-
- Житель
- Сообщения: 915
- Зарегистрирован: 09 мар 2003, 22:46
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Спасибо. Попробую.ura писал(а):В опциях при создании проекта надо кажется убрать "Attributed" и включить Merge Proxy Stub, тогда все будет похоже на VC6, хотя и не совместимо в обратную сторону из-за новой версии ATL. Так что все old fashion проекты с ATL я по возможности создаю в VC6 и потом перетаскиваю на .NET 2003.
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Не стал пробовать с VC 6.0, т.к увидел, что .NET перегенирирует прокси в соответствии с любыми более или менее вменяемыми измениями idl описаний интерфейсов вручную. И это хорошо. Умная штучка.
Но вот наткнулся на вопрос в .NET 2003 о создании дополнительных интерфейсов. Наверное, я тупой... Упростим задачу для простоты изложения.
Есть COM ATLSomeObject объект, который имеет единственный интефейс IATLSomeObject, имеющий единственный метод Message( void ) (бибикает или печатает чего).
Надо добавить второй интерфейс IATLSomeObject2, имеющий одноимённый метод Message(void) (бибикает или печатает немного по-другому).
Как сделать... Читаем MSDN. Там две возможности. Выбираем халявную ... упс визард не хочет ничего добавлять несмотря на то, что макро BEGIN_COM_MAP я уже добавил (как не добавить, ведь MS говорит, что без этого не будет работать... а оно хоть с этим, хоть без этого не печатает...). Это непонятность # 1. Почему визард не помогает быстренько приладить новый интерфейс.
Ладно, перехожу к первому не халявному способу, что без визарда. Руками добавляю в idl второй интерфейс IATLSomeObject2 с заветным методом Message. Пробую в меню "Implement interface". Печатает, собака. И, что интересно, совершенно безразлично определил я ранее BEGIN_COM_MAP, или не определил. Это непонятность # 2. Непонятность это потому, что как сказано в MSDN, без всемогущего BEGIN_COM_MAP вроде как вообще и не добавить дополнительный интерфейс. А добавляется ведь...
Ладно, думаю, хоть сервер и собирается без ошибок и предупреждений, но клиент уж точно не будет работать, поскольку, я заветный макро BEGIN_COM_MAP закоментировал, а без него, вроде как и не будет QueryInterface пахать по заверениям MS. Наивный... Работает, ведь.
Это непонятность # 3. и самая большая непонятность. Как компилятор .NET 2003, работая с ATL проектом, умеет сообразить только на основании наследования интерфейса (чисто C++ наследование, см. ниже;c таким же успехом можно было бы отнаследоваться от чего угодно, не связанного с COM), что надо построить соответствующую правильную DllGetClassObject, если мы не определяли в классе COM_INTERFACE_ENTRY.
Для простоты, привожу очень простой код сервера и клиента. Без всяких проверок на фэйлыд. Клиент намерено сделан без smart poiners, чтобы за спиной ничего не стояло (понятное, дело что со смарт поинтерами аналогичный клиент радостно работает тоже). Сервер в одном .h файлев основном.
Сервер
Клиент
Спасибо, если кто-то прояснит мне эти ньюансы.
Но вот наткнулся на вопрос в .NET 2003 о создании дополнительных интерфейсов. Наверное, я тупой... Упростим задачу для простоты изложения.
Есть COM ATLSomeObject объект, который имеет единственный интефейс IATLSomeObject, имеющий единственный метод Message( void ) (бибикает или печатает чего).
Надо добавить второй интерфейс IATLSomeObject2, имеющий одноимённый метод Message(void) (бибикает или печатает немного по-другому).
Как сделать... Читаем MSDN. Там две возможности. Выбираем халявную ... упс визард не хочет ничего добавлять несмотря на то, что макро BEGIN_COM_MAP я уже добавил (как не добавить, ведь MS говорит, что без этого не будет работать... а оно хоть с этим, хоть без этого не печатает...). Это непонятность # 1. Почему визард не помогает быстренько приладить новый интерфейс.
Ладно, перехожу к первому не халявному способу, что без визарда. Руками добавляю в idl второй интерфейс IATLSomeObject2 с заветным методом Message. Пробую в меню "Implement interface". Печатает, собака. И, что интересно, совершенно безразлично определил я ранее BEGIN_COM_MAP, или не определил. Это непонятность # 2. Непонятность это потому, что как сказано в MSDN, без всемогущего BEGIN_COM_MAP вроде как вообще и не добавить дополнительный интерфейс. А добавляется ведь...
Ладно, думаю, хоть сервер и собирается без ошибок и предупреждений, но клиент уж точно не будет работать, поскольку, я заветный макро BEGIN_COM_MAP закоментировал, а без него, вроде как и не будет QueryInterface пахать по заверениям MS. Наивный... Работает, ведь.
Это непонятность # 3. и самая большая непонятность. Как компилятор .NET 2003, работая с ATL проектом, умеет сообразить только на основании наследования интерфейса (чисто C++ наследование, см. ниже;c таким же успехом можно было бы отнаследоваться от чего угодно, не связанного с COM), что надо построить соответствующую правильную DllGetClassObject, если мы не определяли в классе COM_INTERFACE_ENTRY.
Для простоты, привожу очень простой код сервера и клиента. Без всяких проверок на фэйлыд. Клиент намерено сделан без smart poiners, чтобы за спиной ничего не стояло (понятное, дело что со смарт поинтерами аналогичный клиент радостно работает тоже). Сервер в одном .h файлев основном.
Сервер
Код: Выделить всё
#pragma once
#include "resource.h"
//
// IATLSomeObject interface
//
[
object,
uuid("456EDE06-67D6-4B2B-8A1A-D502850479EA"),
dual, helpstring("Interface # 1"),
pointer_default(unique)
]
__interface IATLSomeObject : IDispatch
{
[id(1), helpstring("method Message")] HRESULT Message(void);
};
//
// IATLSomeObject2 interface
//
[
object,
uuid("8F08C8B6-A53E-4d89-8265-988623204FBA"),
dual, helpstring("Interface # 2"),
pointer_default(unique)
]
__interface IATLSomeObject2 : IDispatch
{
[id(1), helpstring("method Message")] HRESULT Message(void);
};
//
// CATLSomeObject
//
[
coclass,
threading("apartment"),
vi_progid("atl_test.ATLSomeObject"),
progid("atl_test.ATLSomeObject.1"),
version(1.0),
uuid("AE3049F3-006D-40A3-8B68-045CF91DD213"),
helpstring("ATLSomeObject Class")
]
class ATL_NO_VTABLE CATLSomeObject :
public IATLSomeObject,
public IATLSomeObject2
{
public:
CATLSomeObject()
{
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
/*
BEGIN_COM_MAP(CATLSomeObject)
COM_INTERFACE_ENTRY(IATLSomeObject)
COM_INTERFACE_ENTRY(IATLSomeObject2)
END_COM_MAP()
*/
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
//
// Interface
//
// IATLSomeObject Methods
public:
STDMETHOD(IATLSomeObject::Message)(void)
{
MessageBox(0, "Interface # 1 Message(void)", "ATLSomeObject", 0);
return S_OK;
}
// IATLSomeObject2 Methods
public:
STDMETHOD(IATLSomeObject2::Message)(void)
{
MessageBox(0, "Interface # 2 Message(void)", "ATLSomeObject", 0);
return S_OK;
}
};
Код: Выделить всё
#include "stdafx.h"
#include <windows.h>
#include <initguid.h>
DEFINE_GUID(CLSID_Object,
0xAE3049F3, 0x006D, 0x40A3, 0x8b, 0x68, 0x4, 0x5c, 0xf9, 0x1d, 0xd2, 0x13);
//
// first interface
//
DEFINE_GUID(IID_Interface1,
0x456EDE06, 0x67D6, 0x4B2B, 0x8a, 0x1a, 0xd5, 0x2, 0x85, 0x4, 0x79, 0xea);
interface Interface1 : public IDispatch
{
STDMETHOD( InterfaceMessage ) () PURE;
};
//
// second interface
//
DEFINE_GUID(IID_Interface2,
0x8F08C8B6, 0xA53E, 0x4d89, 0x82, 0x65, 0x98, 0x86, 0x23, 0x20, 0x4f, 0xba);
interface Interface2 : public IDispatch
{
STDMETHOD( InterfaceMessage ) () PURE;
};
void main()
{
::CoInitialize( NULL );
Interface1* pInterface1 = NULL;
Interface2* pInterface2 = NULL;
::CoCreateInstance( CLSID_Object, NULL, CLSCTX_INPROC, IID_Interface1,(void **) &pInterface1);
pInterface1->InterfaceMessage();
pInterface1->QueryInterface( IID_Interface2, (void **) &pInterface2);
pInterface2->InterfaceMessage();
pInterface1->Release();
pInterface2->Release();
::CoUninitialize();
}
-
- Частый Гость
- Сообщения: 25
- Зарегистрирован: 23 авг 2005, 00:56
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Спасибо за подсказку.Ren писал(а):А теперь попробуй тоже самое, только без атрибутов.
Тогда и посмотришь что получиться.
Попробовал. Ясно

Ещё вопрос. Attributed класс - очень уж удобное дело. Какое преимущество в использовании проекта с классами без атрибутов?
-
- Житель
- Сообщения: 915
- Зарегистрирован: 09 мар 2003, 22:46
А теперь попробуй удалить proxy-stub DLL, и посмотри что получится. Ты же говоришь что она отдельно компонуется т.е. merge не делался при создании проекта. По идее отдельно PS DLL нужна только если будет использоваться маршаллинг с удаленного компьютера. Опять таки я смортрю что интерфесы наследуются от IDispatch т.е. как я понимаю нестандартные типы в параметрах методов использоваться не будут.
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
А что должно получиться? Удаляется прокси проект. Основной проект с ком сервером также радостно и компилируется. Это прокси имеет в депенденсах основной проект (если удалить основной проект, то прокси длл не скомпилировать).ura писал(а):А теперь попробуй удалить proxy-stub DLL, и посмотри что получится.
уточним, что я говорю.ura писал(а): Ты же говоришь что она отдельно компонуется т.е. merge не делался при создании проекта.
1) Она отдельно компануется, если под компоновкой понимать одну из стадии компиляции компилятором и сборки линкером бинарника.
2) В отдельный проект можно выделить прокси длл, если АТЛ проект выбран без атрибутов. Иначе эта опция не доступна.
3) При компиляции и линковке основного проекта прокси длл не собирается. Ты можешь сам сделать билд прокси, если нужно.
Совершенно точно.ura писал(а): По идее отдельно PS DLL нужна только если будет использоваться маршаллинг с удаленного компьютера.
Не очень тебя понял. Шо имеешь ввиду? Диспатч используется для возможности использования КОМ в скриптовых языках для обеспечения позднего связывания с использованием имен (скриптовые языки не умеют работать непосредственно с ВТБЛ).ura писал(а):Опять таки я смортрю что интерфесы наследуются от IDispatch т.е. как я понимаю нестандартные типы в параметрах методов использоваться не будут.
А так ... если не предусматривается использование с VB (пишем в С и используем, например, в С++ ) - вполне можно обойтись одним Анноун.
-
- Житель
- Сообщения: 915
- Зарегистрирован: 09 мар 2003, 22:46
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Наверное, я всёже не то, что-то делаю, или не понимаю, или это действительно баг у MS
Оба типа COM ( 1) проект ATL attributed; 2) проект ATL с объектами без атрибутов ) прекрасно работают с C++ клиентами, т.е. в обоих случаях оба интерфейса прекрасно разрешаются, так что вызываются методы в коде типа:
Но вот в клиенте C# как оказывается запросить оба интерфейса можно только для COM, который сделан с ATL attributed классами.
Т.е. можно повторить С++ вызовы в C# для обоих интерфейсов в коде типа
Если же объекты сделаны без атрибутов, то ничего подобного не удаётся сделать в клиенте C# (в отличии от C++). В этом случае второго интерфейса не видно напрочь.
Такое ощущение, что всё же в этом моём проекте без аттрибутов где-то косяки... Хоть и работает с C++ клиентами на ура.
Если кто сталкивался подскажите, плз.

Оба типа COM ( 1) проект ATL attributed; 2) проект ATL с объектами без атрибутов ) прекрасно работают с C++ клиентами, т.е. в обоих случаях оба интерфейса прекрасно разрешаются, так что вызываются методы в коде типа:
Код: Выделить всё
Interface1* pInterface1 = NULL;
Interface2* pInterface2 = NULL;
::CoCreateInstance( CLSID_Object, NULL, CLSCTX_INPROC, IID_Interface1,(void **) &pInterface1);
pInterface1->InterfaceMessage();
pInterface1->QueryInterface( IID_Interface2,(void **) &pInterface2);
pInterface2->InterfaceMessage();
Т.е. можно повторить С++ вызовы в C# для обоих интерфейсов в коде типа
Код: Выделить всё
CATLSomeObjectClass coATL_AttributeCls = new CATLSomeObjectClass();
IATLSomeObject InterfaceAttributed1 = ( IATLSomeObject ) coATL_AttributeCls;
IATLSomeObject2 InterfaceAttributed2 = ( IATLSomeObject2 ) coATL_AttributeCls;
InterfaceAttributed1.Message();
InterfaceAttributed2.Message();

Если кто сталкивался подскажите, плз.
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Ты прав. Если ATL CoКлассы без атрибутов и закоментировать макто - не то, что QueryInterface не будет работать (MS говорить тоже, и это логично, о чём и топик-то), а просто компилироваться не будет. Если же проект с атрибутами, то - там по-барабану. Не влияет это макро не на что. Там проект, как ты сам знаешь, в принципе другой, и очень вкусный для таких ленивых и малограмотных, как я. Я об этом и постил в начале топика, типа, в чём и сыр-бор.ura писал(а):Просто пытаюсь разобраться, поскольку совершенно точно при закоментированном
BEGIN_COM_MAP(CATLSomeObject)
END_COM_MAP()
QueryInterface работать не должен, просто там нет IID этих интерфейсов, откуда им взяться тогда.
ПС. Сейчас другая беда прицепилась. Если делать без атрибутов - в шарпе не могу получить второй интерфейс. В ClassView виден только один интерфейс, что определил первым (в С++, в ClassView, естественно видны все интерфейсы, и работает зараза, как часы).
-
- Житель
- Сообщения: 915
- Зарегистрирован: 09 мар 2003, 22:46
А ты проверь TypeLibrary, скорее всего интерфесы читаются оттуда. Это в IDL секции
library YourLibrary
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(0CD249D4-F18D-11D4-967B-0050BAD26351),
helpstring("Yor class")
]
coclass YouCOMObject
{
[default] interface ISomeDefaultShit;
interface ISomeExtraShit;
};
}
Генератор кода вставляет default интерфейс сам, остальное поскольку вставляется руками - надо добавлять в Type Library тоже руками.
Естественно, что интерфес будет работать и без записи в Type Library, если знаешь его IID - то проблем нет, но внешние системы об этом не ведают. Надеюсь это то что требуется.
library YourLibrary
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(0CD249D4-F18D-11D4-967B-0050BAD26351),
helpstring("Yor class")
]
coclass YouCOMObject
{
[default] interface ISomeDefaultShit;
interface ISomeExtraShit;
};
}
Генератор кода вставляет default интерфейс сам, остальное поскольку вставляется руками - надо добавлять в Type Library тоже руками.
Естественно, что интерфес будет работать и без записи в Type Library, если знаешь его IID - то проблем нет, но внешние системы об этом не ведают. Надеюсь это то что требуется.
- ajkj3em
- Маньяк
- Сообщения: 2063
- Зарегистрирован: 12 ноя 2006, 06:53
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
-
- Маньяк
- Сообщения: 2803
- Зарегистрирован: 29 май 2003, 22:29
- Откуда: Магадан - Миссиссага
Вот пока на что наткнулся
Unfortunately, adding additional interfaces to an existing object is harder than you might expect—you have to do a bit of manual labor because there's no wizard to add the interface for you. (It's easy to add another object to your module because there's a wizard to help, however. And there is a wizard to help you implement interfaces for which you have a type library. But because this is a new custom interface, we have no type library to use, so we have to do it by hand.)
Ну и как это соотнести с обещанием счастья от визардов в MSDN?
Unfortunately, adding additional interfaces to an existing object is harder than you might expect—you have to do a bit of manual labor because there's no wizard to add the interface for you. (It's easy to add another object to your module because there's a wizard to help, however. And there is a wizard to help you implement interfaces for which you have a type library. But because this is a new custom interface, we have no type library to use, so we have to do it by hand.)
Ну и как это соотнести с обещанием счастья от визардов в MSDN?
