Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 31.05.13 06:41
Оценка:
Вот к примеру имею класс:

class ATL_NO_VTABLE CIStorage :
 public CComObjectRootEx<CComSingleThreadModel>,
 public CComCoClass<CIStorage, &CLSID_DiagReport>,
 public IDispatchImpl<ICIStorage, &IID_ICIStorage, &LIBID_DiagReportLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
...
...
IFACEMETHODIMP (                        // Создает объект, который позволит нам работать с "IStorage interface"
 _Out_  CIStorage  **pCIStorage,
 _Out_  BOOL       *bResult = 0
);


CreateObjectStorage предназначен для создания и возврата в параметре opIStorage экземпляра объекта класса.

В idl интерфейс представлен как:

[ object,
  uuid( C002768D-287A-4BC8-B098-CDFC74BA9A16 ),
  dual,
  helpstring( "IStorage Interface" ),
  pointer_default(unique)
]

interface ICIStorage : IDispatch {
[ id(0),  
  helpstring( "Create object foe work with IStorage interface" ) 
] HRESULT CreateObjectStorage(
 [out]         CIStorage  **pCIStorage,
 [out, retval] BOOL       *bResult
);


Но idl компилируется с ошибкой:

Error 1 error MIDL2025: syntax error : expecting a type specification near "CIStorage" ...

Как подружить MIDL с CIStorage
Re: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 31.05.13 10:25
Оценка: 2 (1)
Здравствуйте, vladimirmir2013, Вы писали:

V>... idl компилируется с ошибкой:

V>Error 1 error MIDL2025: syntax error : expecting a type specification near "CIStorage" ...
V> Как подружить MIDL с CIStorage

Нужно возвращать не конкретную реализацию интерфейса, а сам интерфейс. Тогда будет правильно с точки зрения СОМа. Т.е.
не HRESULT CreateObjectStorage([out] CIStorage **pCIStorage, [out, retval] BOOL *bResult),
а HRESULT CreateObjectStorage([out] ICIStorage **pCIStorage, [out, retval] BOOL *bResult).



V> CreateObjectStorage предназначен для создания и возврата в параметре opIStorage экземпляра объекта класса.

Лучше поменять параметры, т.к. pCIStorage нужен больше, чем bResult, т.е. HRESULT CreateObjectStorage([out] BOOL *bResult, [out, retval] ICIStorage **pCIStorage).
А ещё лучше убрать параметр bResult и передавать код ошибки в HRESULT, который возвращается самой функцией, т.е. HRESULT CreateObjectStorage([out, retval] ICIStorage **pCIStorage).
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 31.05.13 12:00
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>А ещё лучше убрать параметр bResult и передавать код ошибки в HRESULT, который возвращается самой функцией ...


Вообщем то начал писать ArctiveX для обеспечения работы с compound files.
Как написать wrapper для WINAPI MSDN в основном понятно, но хотелось бы сделать интерфейс к этому API через ActiveX.

Так как планируется use этот ActiveX в 1С, то учитывая специфику 1С как раз и использую второй параметр для возврата результата
выполнения операции.

oDiagReport = СоздатьОбъект( "DiagReport" );

oIStorage = "";

VpКодВозврата = oDiagReport.CreateObjectStorage( oIStorage ); // Создаю объект /oIStorage /, который позволит работать с API IStorage

Ну а затем use oIStorage для работы с IStorage.
Конкретно для метода CreateObjectStorage вообще то говоря ни какой код возврата не требуется /будем считать что переполнения memory и других происшествий не будет.../, но
для успокоения совести программиста и для единообразия оставлю.

Вообще то планирую /и делаю. Это у меня не хобби, а этот ActiveX будет use в проекте на 1С/ в
ActiveX предоставить interface для IStorage, Istream, ...

Хотелось бы знать твое мнение на мой подход к реализации функциональности ActiveX.
Re[3]: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 31.05.13 14:48
Оценка:
Здравствуйте, vladimirmir2013, Вы писали:

V> Хотелось бы знать твое мнение на мой подход к реализации функциональности ActiveX.


Это тебе лучше с шефом своим обсудить, со мной-то к чему? Нормальный подход, если решает твою задачу. Я, правда, 1С не знаю, поэтому ничего лучшего тебе посоветовать не могу.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 31.05.13 15:30
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Это тебе лучше с шефом своим обсудить, со мной-то к чему?


Извени я тебе не льщу, но по твоим постам /и более ранним/ отношу тебя к разряду профессионалов.
ActiveX я делаю не с прицелом на 1С, а для возможности работать с compound files в Automation
/ну немножко учитываю и интересы 1С/.
Да и хороший фундамент для дома важен сам по себе.
Re[2]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 01.06.13 18:55
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, vladimirmir2013, Вы писали:


Vi2>Нужно возвращать не конкретную реализацию интерфейса, а сам интерфейс. Тогда будет правильно с точки зрения СОМа. Т.е.

Vi2>не HRESULT CreateObjectStorage([out] CIStorage **pCIStorage, [out, retval] BOOL *bResult),
Vi2>а HRESULT CreateObjectStorage([out] ICIStorage **pCIStorage, [out, retval] BOOL *bResult).

Нет здесь я хочу получить не pointers to interfaces.
Pointers to interfaces я получаю так /дан пример получения pointers to interface IIStorage/:

[
 object,
 uuid(39479515-AD29-472B-A1FB-1ABE35C36F73),
 dual,
 helpstring( "IDiagReport Interface" ),
 nonextensible,
 pointer_default(unique)
]
interface IDiagReport : IDispatch{

...
...

[ id(5),  
  helpstring( "Get pointer to IIStorage interface" ) 
] HRESULT GetIIStorage(
 [out, retval] IIStorage  **pIIStorage
);

IFACEMETHODIMP CDiagReport::GetIIStorage(
 _Out_  IIStorage  **pIIStorage_
) {
 HRESULT  hr = S_OK;

 hr = CComObject< AIStorage >::CreateInstance( &pIIStorage );

 hr = pIIStorage->QueryInterface(
  IID_IIStorage,
  (void **)&pIIStorage
 );

 *pIIStorage_ = pIIStorage;

 return  hr;

}                                                          // IFACEMETHODIMP CDiagReport::GetIStorage(


А вот к примеру берем реализацию interface IIStorage:


class ATL_NO_VTABLE AIStorage :
 public CComObjectRootEx<CComSingleThreadModel>,
 public CComCoClass<CIStorage, &CLSID_DiagReport1C>,
 public IDispatchImpl<IIStorage, &IID_IIStorage, &LIBID_DiagReportLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{

...
...


Чего я хочу достичь в этом интерфейсе.
Каждый storage может выступать как контейнер для других storage и stream.
В то же время для того, чтобы работать с storage его нужно открыть ...
Вообщем в какой-либо программе может возникнуть необходимость иметь несколько экземпляров класса,
реализующего IIStorage /в конце концов ни через один же объект класса работать с storage .../.
Вот собственно для этого и хочу предоставить возможность получать новый экземпляр класса class ATL_NO_VTABLE AIStorage :.

Экземпляр класса получаю так:


 CComObject< AIStorage >  *m_pAIStorage;                   // Ссылка на экземпляр класса

 hr = CComObject< AIStorage >::CreateInstance( &m_pAIStorage );

 *pICIStorage = (IIStorage *)m_pAIStorage;

 Если заглянуть в atlcom.h, то видим:

template <class Base>
HRESULT WINAPI CComObject<Base>::CreateInstance(
    _COM_Outptr_ CComObject<Base>** pp) throw()
{
...
...
 ATLTRY(p = _ATL_NEW CComObject<Base>())



Т.е. экземпляр класса создается с помощью new.

Для проверки работы методов use 1C.
Но ты не обращай на это внимание в 1С нет ни чего замысловатого при работе с ActiveX
/все просто и удобно. Хотя в принципе тоже самое можно проделать use например javascript .../

Сейчас у меня возникла проблема состоящая в том, что в коде

глIIStorage = глDiagReport1C.GetIStorage(); // Get pointer to IIStorage interface

// Создаю экземпляр класса class ATL_NO_VTABLE AIStorage :
//
глIStorage01 = "";
глIStorage01 = глIIStorage.CreateObjectStorage(); // Создаем объект для работы с каким-либо storage

Так вот /use Visual Studio 2012/ use debugger вижу что экземпляр класса корректно создается.
И далее могу в 1С дальше что то делать. Но при выходе из 1С имею:

Сигнатура проблемы:
Имя события проблемы: BEX
Имя приложения: 1cv7.exe
Версия приложения: 7.70.0.27
Отметка времени приложения: 4573fcb7
Имя модуля с ошибкой: StackHash_5861
Версия модуля с ошибкой: 0.0.0.0
Отметка времени модуля с ошибкой: 00000000
Смещение исключения: PCH_5F_FROM_ntdll+0x00041318
Код исключения: c0000005
Данные исключения: 00000008
Версия ОС: 6.2.9200.2.0.0.400.8
Код языка: 1049
Дополнительные сведения 1: 5861
Дополнительные сведения 2: 5861822e1919d7c014bbb064c64908b2
Дополнительные сведения 3: f3d5
Дополнительные сведения 4: f3d5be0cad2787556264647dc02181c3

Код c0000005 намекает на то, что имеются проблемы с memory.

Что я делаю не правильно?
Re[3]: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 01.06.13 20:18
Оценка:
Здравствуйте, vladimirmir2013, Вы писали:

V> Что я делаю не правильно?


Сложно сказать, скорее всего, основные проблемы в СОМе происходят от неправильной работы со ссылками или некорректного доступа к виртуальной таблице методов вследствие неверного получения указателя, короче, от неиспользования QueryInterface, обычно для оптимизации или из-за небрежности.

Насколько я могу судить по приложенному коду (а в них отсутствуют необходимые данные о типе используемых переменных):
V>IFACEMETHODIMP CDiagReport::GetIIStorage(_Out_  IIStorage  **pIIStorage_) {
V> HRESULT  hr = S_OK;

V> hr = CComObject< AIStorage >::CreateInstance( &pIIStorage );

V> hr = pIIStorage->QueryInterface(IID_IIStorage, (void **)&pIIStorage);

V> *pIIStorage_ = pIIStorage;

V> return  hr;
V>}                                                          // IFACEMETHODIMP CDiagReport::GetIStorage(

и
V> CComObject< AIStorage >  *m_pAIStorage;                   // Ссылка на экземпляр класса

V> hr = CComObject< AIStorage >::CreateInstance( &m_pAIStorage );

V> *pICIStorage = (IIStorage *)m_pAIStorage;

переменные pICIStorage и pIIStorage содержат указатели с опасным значением счётчика ссылок, т.е. в любой момент способные указывать "в никуда".

В первом случае pIIStorage содержит указатель с увеличенным значением счётчика ссылки, но отдаёт его переменной pIIStorage_ и становится опасным для последующего использования. Если не считать тут ещё возможных проблем с С++ приведением типов CComObject<AIStorage>* и IIStorage*. Лучше так и делать: hr = pIIStorage->QueryInterface(IID_IIStorage, (void **) pIIStorage_); или же hr = pIIStorage->QueryInterface(pIIStorage_);

Вот втором случае pICIStorage, как и m_pAIStorage, сразу содержат опасный указатель с нулевым значением счётчика ссылки.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 02.06.13 09:36
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>В первом случае pIIStorage содержит указатель с увеличенным значением счётчика ссылки, но отдаёт его переменной pIIStorage_ и становится опасным для последующего использования.


Ни как не могу понять почему если я присваиваю какому-то указателю другой, то последний становится опасен.
Ведь по идее я всего лишь создаю своего рода алиас.

Vi2> Если не считать тут ещё возможных проблем с С++ приведением типов CComObject<AIStorage>* и IIStorage*.


MIDL же не пропустит такое объявление:

[ id(0),  
  helpstring( "Create object for work with IIStorage interface" ) 
] HRESULT CreateObjectStorage(                             // Создает объект, который позволит нам работать с "IIStorage interface"
 [out, retval] AIStorage  **pIIStorage
);


Как же клиенту отдать ссылку на созданный объект класса. Или вообще его клиенту не отдавать, а завести скажем вектор в котором будут
сохраняться созданные объекты, ну а клиент пусть указывает индекс объекта с который ему нужен.
Топчусь на месте ни как не могу понять как правильно организовать код для выше сказанного.

Да что касается метода IFACEMETHODIMP GetIIStorage( ... );, то с ним вроде все Ok. И старый код работает и посоветанный тобой.
В 1С я могу в любом месте use адрес интерфейса и вызывать какой-нибудь метод.

Ниже приведена ссылка на архив в котором имеются некоторые исходники.

здесь
Re[5]: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 02.06.13 13:06
Оценка:
Здравствуйте, vladimirmir2013, Вы писали:

V> Ни как не могу понять почему если я присваиваю какому-то указателю другой, то последний становится опасен.

V> Ведь по идее я всего лишь создаю своего рода алиас.

Ты сам писал, что "... экземпляр класса создается с помощью new", значит, он уходит с помощью delete, но этот delete обычно вызывает код в методе IUnknown::Release(), когда счётчик ссылок объекта после декремента станет равным 0. После этого печального события этого экземпляра класса не будет, и указатель на него, сохраняемый где-то, становится невалидным, т.е. указывающим на фактически пустое место.

V> Как же клиенту отдать ссылку на созданный объект класса. Или вообще его клиенту не отдавать, а завести скажем вектор в котором будут

V> сохраняться созданные объекты, ну а клиент пусть указывает индекс объекта с который ему нужен.
V> Топчусь на месте ни как не могу понять как правильно организовать код для выше сказанного.

Клиент попросил IStorage у объекта, он ему должен его предоставить. Если объект имеет внутренний IStorage, с которым сам этот объект работает, то нужно передать клиенту этот хранимый указатель и увеличить число ссылок у него. Если объект не имеет внутреннего IStorage, то нужно создать и отдать клиенту указатель на созданный объект, предварительно увеличив число ссылок у него, и у себя его не удалять и не хранить для удаления.

V> Ниже приведена ссылка на архив в котором имеются некоторые исходники.

V> url

При всём своём старании я не смог скачать DiagReport.7z.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 02.06.13 16:41
Оценка:
Здравствуйте, vladimirmir2013, Вы писали:

V> Как же клиенту отдать ссылку на созданный объект класса. Или вообще его клиенту не отдавать, а завести скажем вектор в котором будут

V> сохраняться созданные объекты, ну а клиент пусть указывает индекс объекта с который ему нужен.
V> Топчусь на месте ни как не могу понять как правильно организовать код для выше сказанного.

Архив я получил, но затрудняюсь сказать что-либо по коду, т.к. замысел остался непонятым. Хотя, нет, (1**) этот код

IFACEMETHODIMP CDiagReport::put_FullPathToMD(BSTR Str) {

 m_cfFullPathFile = SysAllocString( Str );
 return S_OK;
}

ведёт к утечке памяти, т.к. старое значение BSTR будет утеряно переменной m_cfFullPathFile. Нужно использовать CComBSTR вместо BSTR в описании m_cfFullPathFile.

Также я могу тебе показать свой код (//** — комментарии именно для тебя) создания похожего на твой объекта:

STDMETHODIMP IXXXObject::get_Properties(/*[out,retval]*/ IXXXObjectProperties* *pVal)

  {
    HRESULT hr = E_POINTER;

    if (pVal)
    {
      *pVal = NULL;

      CComObject<CIXXXObjectProperties> *p; //** объект, реализующий функциональность IXXXObjectProperties (описание ниже)

      //** Фактически, это коллекция свойств объекта, представляющая свойство как отдельной СОМ объект. Зависит от создающего
      //** его объекта, поэтому метод класса Init позволяет получить нужный объект, сохранить и при необходимости перевести указатель на
      //** интерфейс IXXXObject в необходимый С++ класс CIXXXObject (здесь не показанный) простым кастом (CIXXXObject*) (IXXXObject*) pObject,
      //** потому что только CIXXXObject может создавать CIXXXObjectProperties и передавать туда свой указатель (я уже не помню, почему было
      //** сделано именно так).

      //** class ATL_NO_VTABLE CIXXXObjectProperties
      //**     : public CComObjectRoot
      //**
      //** (2**) Заметь, нет public CComCoClass<>, потому что он не создаваемый клиентом, а только одним из моих объектов. Так что 
      //** твой AIStorage также может его не иметь, если нет необходимости в его коклассе
      //**
      //**     , public IDispatchImpl<IXXXObjectProperties, &IID_IXXXObjectProperties, &LIBID_XXXXXXLib, MAJOR,MINOR>
      //**     , public ISupportErrorInfoImpl<&IID_IXXXObjectProperties>
      //**     {
      //**         CComPtr<IXXXObject>    pObject;
      //**     public:
      //**         CIXXXObjectProperties() :pObject(NULL) {}
      //**         // Псевдо-конструктор
      //**         void Init(/*[in]*/ IXXXObject *p) { pObject = p; } //** в этом присваивании вызывающий объект сохраняется в памяти
      //**                                                            //** потому что CComPtr.operator= увеличивает число ссылок вызывающего
      //**                                                            //** объекта и сохраняет его для использования в качестве донора
      //**                                                            //** данных

      if (SUCCEEDED(hr = CComObject<CIXXXObjectProperties>::CreateInstance(&p))) //** создаётся этот объект
      {
        p->Init(this); //** наполняется данными, как обычный С++ класс

        if (FAILED(hr = p->QueryInterface(pVal))) //** запрашивается нужный интерфейс (всегда S_OK, но на всякий пожарный)
          delete p; //** в случае ошибки его никто не удалит
      }
    }
    return hr;
  }

Клиент, получивший коллекцию свойств объекта, может освободить сам объект, но коллекция сама по себе хранит указатель на объект, не даёт ему разрушиться раньше времени и использует данные объекта. Самому объекту нет необходимости хранить или считать созданные таким образом коллекции свойств — сколько нужно будет клиенту, столько и будет создано.

Если же объекту самому нужна такая коллекция, то ты можешь создать по этому же сценарию, сохранить у главном объекте увеличенную ссылку и отдавать по запросу хранимый таким образом интерфейс подчинённого объекта. Конечно, нужно продумать сценарии и что делать, если 1) главный объект удалён, а отданный ещё существует, 2) главный объект изменился во время существования отданного объекта.

Но сохранять в векторах, мапах или ещё в чём-то отданные СОМ указатели необходимости нет (и даже желательно проектировать так, чтобы её и не было), т.к. СОМ объекты живут сами по себе и удаляются по мере ненужности самостоятельно.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 02.06.13 18:56
Оценка:
Здравствуйте, Vi2, Вы писали:

В FACEMETHODIMP AIStorage::CreateObjectStorage(...) добавил строку увеличивающую число ссылок на созданный экземпляр объекта и 1С
перестала вылетать...

 hr = CComObject< AIStorage >::CreateInstance( &m_pAIStorage );
 *pICIStorage = (IIStorage *)m_pAIStorage;
 m_pAIStorage->AddRef();


Пожалуй сегодня уже работать не буду, а завтра начну реализовывать методы для IStorage и IStream.
Насчет кода из которого трудно понять чего же человек хотел — согласен.
Объясняется это тем, что пробывал так и эдак и на всякий случай оставил и то и это ...

Я понимаю, что interfaces от реализации не зависят и это абстракция над какими-то классами.
Но классы по большей части начинают быть полезны, когда мы реализовываем какие-то экземпляры объектов ...
Все таки возвращаясь к интерфейсу IStorage.
Ну вот написал я класс, который его реализует /ну и понятно реализовал коды методов .../.
Вот беру открываю compound file. Понятно что в классе я имею members, которые держат разную информацию об storage.
Теперь мне нужно внутри этого storage открыть какой-то другой storage.
На C++ все понятно. Создаю объект, который держит данные об корневом storage.
Возникла необходимость открыть несколько других storage и сохранить об них данные, то создаю например для каждого
из них объект и радуюсь.
А в COM вот никак не пойму как такой подход реализовать. В MIDL я не могу в методах use параметры с типами,
которые MIDL не понимает.
Как же я тогда буду use свои классы если в методах intrfaces я не могу на них ссылаться.
Re[6]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 02.06.13 19:32
Оценка:
Здравствуйте, Vi2, Вы писали:

В COM в параметрах методов нельзя use void.
А вот заглянул в типы переменных, которые понимает Automation и в частности обратил внимание на VARIANT.
Так вот если в параметрах методов use этот тип, то тогда можно будет передать и адрес и ...
Похоже на правду?
Re[7]: Как определить в методе из interface параметр, ссылающийся на класс
От: Vi2 Удмуртия http://www.adem.ru
Дата: 03.06.13 05:11
Оценка:
Здравствуйте, vladimirmir2013, Вы писали:

V> Я понимаю, что interfaces от реализации не зависят и это абстракция над какими-то классами. Но классы по большей части начинают быть полезны, когда мы реализовываем какие-то экземпляры объектов ...

V> Все таки возвращаясь к интерфейсу IStorage. Ну вот написал я класс, который его реализует /ну и понятно реализовал коды методов .../. Вот беру открываю compound file. Понятно что в классе я имею members, которые держат разную информацию об storage. Теперь мне нужно внутри этого storage открыть какой-то другой storage.
V> На C++ все понятно. Создаю объект, который держит данные об корневом storage. Возникла необходимость открыть несколько других storage и сохранить об них данные, то создаю например для каждого из них объект и радуюсь.
V> А в COM вот никак не пойму как такой подход реализовать. В MIDL я не могу в методах use параметры с типами, которые MIDL не понимает.
V> Как же я тогда буду use свои классы если в методах intrfaces я не могу на них ссылаться.

Никто не мешает тебе реализовывать функциональность на уровне С++ классов, ведь когда ты попадаешь внутрь метода, ты находишься внутри С++ классов и волен использовать их мощь. Мой пример с Init можно ведь расширить по параметрам и передавать туда кучу параметров, как и расширить количество неСОМовских методов. Это вполне допустимо. Однако СОМовские методы ограничены СОМовской спецификацией и передачей указателей на интерфейсы вместо указателей на классы, потому что некоторые СОМ клиенты не понимают С++ классов. С этим нужно считаться.

Можно также, при острой необходимости, определить классы по интерфейсам ИНФО: Как получить Cx из Ix*
Автор: Vi2
Дата: 17.06.02
.

Поэтому если твоему хранилищу понадобилось создать/открыть подхранилище или подпоток, то хранилище создаёт объект управления этим подхранилищем или подпотоком, который блокирует AddRef'ом порождающее хранилище, но в дальнейшем ничем не отличается от поведения, которое ты описал. Основное хранилище — по законам СОМа — не может завершить свою работу, пока созданные под-объекты не завершатся, тем самым обеспечивается работоспособность всех потоков данных. Если же основное хранилище может измениться или должно иметь более высокий приоритет в работе, то нужно это предусматривать в работе и отказывать в обслуживании после изменения/закрытия хранилища.

А VARIANT тебе не поможет, в нём нет ничего нового. Можно грубо считать, что именно через VARIANT и происходит передача данных между COM объектами.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[8]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 03.06.13 11:02
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Поэтому если твоему хранилищу понадобилось создать/открыть подхранилище или подпоток, то хранилище создаёт объект управления этим подхранилищем или подпотоком,


В чем вообще состоит моя задача — реализовать частичную поддержку для 1С 7.7 работать с конфигурацией через WWW.
Каждая конфигурация 7.7. имеет файл содержащий некоторым образом представленный набор meta данных об use справочниках, журналах, ...
Передо мной поставлена пока min задача. Use IE иметь возможность запросить формирование какого-либо отчета.
ActiveX нужен мне для того, чтобы налету вытащить информацию об какой-либо диалоговой форме отчета из meta данных конфигурации.
После этого ActiveX на лету строить на странице диалоговую форму ...
Данные для диалоговых форм будут браться из базы 1С через некий протокол use sockets ...
В целом задача выполнима и вполне понятно как ее решать.

Далее чтобы задать вопрос придется более полно рассказать о том что есть и чего нет.
Вообщем то у меня имеется некий File_.h и File_.cpp, который use в качестве wrapper над всем всем file management Microsoft:
— File Management;
— Directory Management;
— Volume ;
...
— Compound file Management

Решил я часть функционала из этого wrapper завернуть в ActiveX /ну жизнь заставила ...См. выше/.
Ниже представлена часть wrapper над IStorage interface.

class CIStorage : public WCRT::WCRTError {
...
...
// Members
//
ComPtr< IStorage > m_pIStorage; // A pointer to a IStorage * pointer variable that receives the interface pointer to the opened storage
CString m_cfNameStorage; // Full name storage
BOOL m_bManaged; // == TRUE — при уничтожении объекта файл будет закрываться автоматически

Теперь перехожу к вопросу.
Вот вызвал например OpenStorage() из интерфейса AIStorage. В member CIStorage m_pCIStorage; у меня появились данные об открытом storage.
Если я выполню OpenStorage() для другого storage, то я потеряю данные об предыдущем открытом.
Да и клиент мой хочет иметь возможность иметь возможность работать так:

stReport = глIStorage01.OpenStorage( "Report", STGM_READ + STGM_SHARE_EXCLUSIVE ); // Storage с данными об отчетах
stJournal = глIStorage01.OpenStorage( "Journal", STGM_READ + STGM_SHARE_EXCLUSIVE ); // Storage с данными об журналах

Так вот ни как не пойму как этого достичь /хотя вроде что-то начинает уже клеиться/.
Чего я хочу достигнуть в методе AIStorage::CreateObjectStorage — предоставить клиенту получить как stReport, stJournal ...
И при этом, чтобы клиент рассматривал stReport, stJournal ... как самостоятельный объекты, которые он может use для работы с storage.
Т.е. чтобы клиент не просто мог /в терминах 1С/ создать объект
глDiagReport = СоздатьОбъект( "DiagReport" ); /создали объект для работы с ActiveX "DiagReport"/
но мог бы таким же манером use различные interface этого ActiveX создавать экземпляры объектов для интерфейсов /IStorage, IStream, .../
Re[8]: Как определить в методе из interface параметр, ссылающийся на класс
От: vladimirmir2013  
Дата: 03.06.13 18:44
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Никто не мешает тебе реализовывать функциональность на уровне С++ классов, ведь когда ты попадаешь внутрь метода, ты находишься внутри С++ классов и волен использовать их мощь.


Не об этом речь. На C++ я могу наваять что мне вздумается. Как предоставить клиенту use это.

Решил посмотреть как Microsoft организовывает свои ActiveX /уж у них опыта поболее моего. Так что не зазорно и поучиться/.

И так открываем Excel Object Model Reference и параллельно смотрим в TypeLib для EXCEL.EXE.

Посмотрим к примеру на Sheets Object => interface Sheets
--------------------------------------------------------
Рассмотрим Sheets.Copy Method
expression.Copy( Before, After )

Before Optional Variant The sheet before which the copied sheet will be placed. You cannot specify Before if you specify After.
After Optional Variant The sheet after which the copied sheet will be placed. You cannot specify After if you specify Before.

[id(0x00000227), helpcontext(0x0002520a)]
HRESULT Copy(
[in, optional] VARIANT Before,
[in, optional] VARIANT After,
[in, lcid] long lcid
);

А на странички то ссылаются с use ппараметров типа VARIANT и мне думается, что значение
этих параметров и предсталяет или:

тип INT /индекс на item вутри какой-либо коллекции/ или

или

PVOID byref; /ссылка на экземпляр какого-либо класса ответственного за работу с SHeets/

Посмотрим на Sheets.Item Property
---------------------------------
Returns a single object from a collection
expression.Item(Index)

[id(0x000000aa), propget, helpcontext(0x0002520e)]
HRESULT Item(
[in] VARIANT Index,
[out, retval] IDispatch** RHS
);

Т.е. по существу возвращаем адрес экземпляра объекта interface Sheets /одной из страниц/
/экземпляр объекта какого-то C++ класса, реализующего interface Sheets/

Это я к тому, что в AIStorage данные об storage можно хранить в какой-либо коллекции, а доступ
к ним предоставлять двояко:

— с указанием индекса /который можно эмулировать именем storage, числом, .../

глIIStorage.CreateObjectStorage( "Report" );

VpКодВозврата = глIStorage01.OpenStorage(
"Report",
STGM_READ + STGM_SHARE_EXCLUSIVE
);

— или отдавать клиенту ссылку на storage в коллекции
stReport = глIStorage01.OpenStorage( "Report", STGM_READ + STGM_SHARE_EXCLUSIVE ); // Ссылка к экземпляру Storage с данными об отчетах

Вообщем я тебя замучил и себя.
Завтра начну пробывать реализовывать методы интерфейса, которые позволят работать
с объектами выше приведенными способами.

Что касается 1С 7.7, то насколько я понимаю ни кто на нее уже не позарится ...
Так что делать какую-то коммерцию на этом не собираюсь /бесполезно/.
Смысл работы — чему то подучусь и выполню задание начальника.

Знаешь не знаю как у других, а я так не могу приступить к работе если не чувствую
того, что выбранный подход мной подход к решению если уж и не самый лучший, но по крайней мере
мне перед профессионалами не будет стыдно и не скажут, что у него каша в голове.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.