Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Ignoramus  
Дата: 13.07.04 10:28
Оценка:
Помогите плз!

Возникает access violation при drag'n'drop из одного экземпляра моего приложения в другой. Исключение бросается после вызова pUnkForRelease->Release(), не могу понять в чем дело.

Делаю так:

В IDataObject::GetData

class TDataObject : public IDataObject;

HRESULT TDataObject::GetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium)
{
 // ...
 pmedium->tymed = TYMED_HGLOBAL;
 pmedium->hGlobal = ::GlobalAlloc(GHND, nSize);
 pmedium->pUnkForRelease = new TUnknownForRelease(pmedium->hGlobal);
 // ...
}


В drop target'е

void TDropTarget::GetDataObject(IDataObject* pdataobject)
{
 // ...
 STGMEDIUM medium; ::ZeroMemory(&medium, sizeof(STGMEDIUM));
 pdataobject->GetData(&Format, &medium);
 // ...

 ::ReleaseStgMedium(&medium);
}


В IUnknown:

class TUnknownForRelease : public IUnknown
{
 private: 
  int nRefs;
  HGLOBAL hGlobal;
 public:
  TUnknownForRelease(HGLOBAL hglobal) {hGlobal = hglobal; nRefs = 1;}
  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppvObject);
  ULONG STDMETHODCALLTYPE AddRef(void);
  ULONG STDMETHODCALLTYPE Release(void);
};
// ....
ULONG TUnknownForRelease::Release(void)
{
 nRefs --;
 if (nRefs == 0)
 {
  if (hGlobal)
  {
   ::GlobalFree(hGlobal);
   hGlobal = NULL;
  }
  // если заремить эту строчку, то все ок, но тогда объект остается неосвобожденным?
  delete this;
  return 0;
 }
 return nRefs;
}
Re: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Tom Россия http://www.RSDN.ru
Дата: 13.07.04 10:57
Оценка:
I>
I>class TDataObject : public IDataObject;

I>HRESULT TDataObject::GetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium)
I>{
I> // ...
I> pmedium->tymed = TYMED_HGLOBAL;
I> pmedium->hGlobal = ::GlobalAlloc(GHND, nSize);
I> pmedium->pUnkForRelease = new TUnknownForRelease(pmedium->hGlobal);
pmedium->pUnkForRelease->AddRef(); // Копируем "на верх", а значит должны увеличить кол-во ссылок
I> // ...
I>}
I>
Народная мудрось
всем все никому ничего(с).
Re[2]: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Vi2 Удмуртия http://www.adem.ru
Дата: 13.07.04 12:23
Оценка:
Здравствуйте, Tom, Вы писали:

I>> pmedium->tymed = TYMED_HGLOBAL;

I>> pmedium->hGlobal = ::GlobalAlloc(GHND, nSize);
I>> pmedium->pUnkForRelease = new TUnknownForRelease(pmedium->hGlobal);
Tom>pmedium->pUnkForRelease->AddRef(); // Копируем "на верх", а значит должны увеличить кол-во ссылок
I>> // ...

Вряд ли, со счетчиком все в порядке.

Скорее всего, GHND не держит в память само значение hGlobal, поэтому вполне могло переместиться в силу других причин. Т.о. налицо рассогласование pmedium->hGlobal и TUnknownForRelease::hGlobal.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Ignoramus  
Дата: 13.07.04 12:40
Оценка:
Здравствуйте, Tom, Вы писали:

I>>
I>> pmedium->pUnkForRelease = new TUnknownForRelease(pmedium->hGlobal);
Tom>pmedium->pUnkForRelease->AddRef(); // Копируем "на верх", а значит должны увеличить кол-во ссылок
I>> // ...
I>>}
I>>


Дело в том, что в конструкторе TUknownForRelease я сразу присваиваю nRefs = 1, так что не думаю что в этом дело.
Re[3]: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Ignoramus  
Дата: 13.07.04 13:01
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Скорее всего, GHND не держит в память само значение hGlobal, поэтому вполне могло переместиться в силу других причин. Т.о. налицо рассогласование pmedium->hGlobal и TUnknownForRelease::hGlobal.


Позволю себе с Вами не согласиться. Пусть себе память переместилась, но хендл на память, который выделила GlobalAlloc(GMEM_MOVEABLE, ...) должен был остаться прежним. Тем более, что выделение и освобождение памяти происходит в одном процессе — метод IDataObject::GetData вызывается в принимающем приложении и ReleaseStgMedium там же.

Кроме того, мне кажется, исключение вылетает именно в случае если присутствует строка "delete this" в TUnknownForRelease::Release(). Без нее с hGlobal никаких проблем не появляется.
Re[4]: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Ignoramus  
Дата: 13.07.04 13:06
Оценка:
Более того, если этот хендл мог бы меняться, как Вы говорите, я тогда не представляю себе как должен работать механизм pUnkForRelease Что он сможет сделать, если все изменилось и исходные хендлы потеряны на момент его активации?
Re[5]: Вопрос по Drag'n'Drop STGMEDIUM->pUnkForRelease
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.07.04 03:52
Оценка:
Здравствуйте, Ignoramus, Вы писали:

I>Позволю себе с Вами не согласиться. Пусть себе память переместилась, но хендл на память, который выделила GlobalAlloc(GMEM_MOVEABLE, ...) должен был остаться прежним. Тем более, что выделение и освобождение памяти происходит в одном процессе — метод IDataObject::GetData вызывается в принимающем приложении и ReleaseStgMedium там же.


I>Кроме того, мне кажется, исключение вылетает именно в случае если присутствует строка "delete this" в TUnknownForRelease::Release(). Без нее с hGlobal никаких проблем не появляется.


I>Более того, если этот хендл мог бы меняться, как Вы говорите, я тогда не представляю себе как должен работать механизм pUnkForRelease Что он сможет сделать, если все изменилось и исходные хендлы потеряны на момент его активации?


Согласен. Но из кода, который был приведен, другое предположение и не последовало бы — там более-менее все в порядке. Единственное: nRefs обычно защищают при многопоточности и т.п. Раннее освобождение объекта было бы легко установить.

Через "delete this" в Release удаляется каждый (по крайней мере в ATL) СОМ объект, и никто не жалуется на вылет приложений из-за этого. Чаще "вылетают" при этом операторе, когда библиотека поддержки (по очистке ли ресурсов, при обращении к СОМу etc.) выгрузилась.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.