проблема с shell extension
От: dkotlyarov Россия  
Дата: 24.07.05 19:49
Оценка:
Пишу shell extension (по руководству Michael Dunn, но без ATL), которое должно добавлять пункты в контекстное меню explorer-а. Реализовал интерфейсы IShellExtInit и IContextMenu, однако Windows упорно отказывается запрашивать интерфейс IContextMenu.

Кроме того, компонент по-разному ведет себя при вызове меню на рабочем столе и в окне explorer-a. Если, вызывая контекстное меню на рабочем столе, система по крайней мере вызывает метод IShellExtInit::Initialize, то при вызове из explorer-а не происходит даже этого! Класс просто создается, а потом разрушается.

Подскажите, пожалуйста, возможные причины. Заренее благодарен.

Windows XP SP2, Visual C++ .NET.


class CShellExt : public IShellExtInit, public IContextMenu
{
protected:
  long  m_lRef;

public:
  CShellExt();
  ~CShellExt();

public:
  // IUnknown
  STDMETHOD(QueryInterface(REFIID, void**));
  STDMETHOD_(ULONG, AddRef());
  STDMETHOD_(ULONG, Release());

  // IShellExtInit
  STDMETHOD(Initialize(LPCITEMIDLIST, IDataObject*, HKEY));

  //IContextMenu
  STDMETHOD(GetCommandString(UINT, UINT, UINT *, LPSTR, UINT));
  STDMETHOD(InvokeCommand(LPCMINVOKECOMMANDINFO));
  STDMETHOD(QueryContextMenu(HMENU, UINT, UINT, UINT, UINT));
};


CShellExt::CShellExt()
{
  m_lRef = 0;
  InterlockedIncrement(&g_lObjs);
}

CShellExt::~CShellExt()
{
  InterlockedDecrement(&g_lObjs);
}

STDMETHODIMP CShellExt::QueryInterface(REFIID riid, void** ppv)
{
  *ppv = 0;
  if (riid == IID_IUnknown || riid == IID_IShellExtInit || riid == IID_IContextMenu){
    *ppv = this;
    AddRef();
    return(S_OK);
  }
  return (E_NOINTERFACE);
}

STDMETHODIMP_(ULONG) CShellExt::AddRef()
{
  return InterlockedIncrement(&m_lRef);
}

STDMETHODIMP_(ULONG) CShellExt::Release()
{
  if (InterlockedDecrement(&m_lRef) == 0){
    delete this;
    return 0;
  }
  return m_lRef;
}

STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pDataObj, HKEY hProgID)
{
  MessageBox(NULL, L"Initialize", L"", MB_OK);
  return S_OK;
}

STDMETHODIMP CShellExt::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{
  MessageBox(NULL, L"QueryContextMenu", L"", MB_OK);
  return S_OK;
}

STDMETHODIMP CShellExt::GetCommandString(UINT idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
  MessageBox(NULL, L"GetCommandString", L"", MB_OK);
  return S_OK;
}

STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
  MessageBox(NULL, L"InvokeCommand", L"", MB_OK);
  return S_OK;
}
Re: проблема с shell extension
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 25.07.05 04:06
Оценка:
Здравствуйте, dkotlyarov, Вы писали:

D>Класс просто создается, а потом разрушается.


Добавь трассировку вызовов QueryInterface

D>Подскажите, пожалуйста, возможные причины. Заренее благодарен.


class CShellExt : public IShellExtInit, public IContextMenu
//...
STDMETHODIMP CShellExt::QueryInterface(REFIID riid, void** ppv)
{
 *ppv = 0;

 if (riid == IID_IUnknown || riid == IID_IShellExtInit || riid == IID_IContextMenu)
 {
  *ppv = this;
 
  AddRef();
  return(S_OK);
 }

 return (E_NOINTERFACE);
}


Очень странная реализация QueryInterface. Как минимум для IID_IContextMenu нужно было использовать
*ppv=static_cast<IContextMenu*>(this);
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: проблема с shell extension
От: dkotlyarov Россия  
Дата: 25.07.05 14:42
Оценка:
КД>
КД>class CShellExt : public IShellExtInit, public IContextMenu
КД>//...
КД>STDMETHODIMP CShellExt::QueryInterface(REFIID riid, void** ppv)
КД>{
КД> *ppv = 0;

КД> if (riid == IID_IUnknown || riid == IID_IShellExtInit || riid == IID_IContextMenu)
КД> {
КД>  *ppv = this;
 
КД>  AddRef();
КД>  return(S_OK);
КД> }

КД> return (E_NOINTERFACE);
КД>}
КД>


КД>Очень странная реализация QueryInterface. Как минимум для IID_IContextMenu нужно было использовать

КД>
КД>*ppv=static_cast<IContextMenu*>(this);
КД>


Спасибо, часть проблем решилась с внесением данной поправки.
Однако я не совсем понял, почему в данном случае необходимо применять static_cast, ведь мы возвращаем указатель на класс через void*, и, таким образом, не должно происходить сужение типа...

И еще, почему

Как минимум для IID_IContextMenu нужно было использовать...

Это не относится в той же мере и к IID_IShellExtInit?
Re[3]: проблема с shell extension
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 25.07.05 15:44
Оценка:
Здравствуйте, dkotlyarov, Вы писали:

D>Спасибо, часть проблем решилась с внесением данной поправки.

D>Однако я не совсем понял, почему в данном случае необходимо применять static_cast, ведь мы возвращаем указатель на класс через void*, и, таким образом, не должно происходить сужение типа...

static_cast обеспечивает корректное "преобразование" this к указателю на базовый класс IContextMenu. А именно, возвращает указатель, который ссылается на тот участок памяти, где начинаются данные интерфейса IContextMenu — там только указатель на таблицу виртуальных методов хранится.

присваивание вида
*ppv = this;

в твоем случае всегда возвращало указатель на первый в списке наследуемый класс — IShellExtInit. Для IID_IShellExtInit, IID_IUnknown это работало, а для IID_IContextMenu — нет

D>И еще, почему

Как минимум для IID_IContextMenu нужно было использовать...

Это не относится в той же мере и к IID_IShellExtInit?


И к нему, в принципе, тоже. А для IUnknown можно, например, возвращать тот же указатель, что и для IShellExtInit
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: проблема с shell extension
От: dkotlyarov Россия  
Дата: 26.07.05 08:32
Оценка:

КД>Добавь трассировку вызовов QueryInterface



Пункт меню успешно добавляется при вызове контекстного меню на рабочем столе, а при вызове из explorer-а — нет
Я определил последовательность вызовов методов CShellExt в случае с рабочим столом и с explorer-ом. Из explorer-а почему-то вообще не вызывается IShellExtInit::Initialize и не запрашивается интерфейс IContextMenu...

Вот результат:

Desktop (тут все нормально):
CShellExt::CShellExt
CShellExt::QueryInterface {000214E8-0000-0000-C000-000000000046} IShellExtInit
CShellExt::AddRef
CShellExt::AddRef
CShellExt::Release
CShellExt::QueryInterface {000214E8-0000-0000-C000-000000000046} IShellExtInit
CShellExt::AddRef
CShellExt::Release
CShellExt::Initialize
CShellExt::QueryInterface {000214E4-0000-0000-C000-000000000046} IContextMenu
CShellExt::AddRef
CShellExt::QueryInterface {FC4801A3-2BA9-11CF-A229-00AA003D7352} IObjectWithSite
CShellExt::QueryInterface {79EAC9EE-BAF9-11CE-8C82-00AA004BA90B} IInternetSecurityManager
CShellExt::QueryContextMenu
CShellExt::AddRef
CShellExt::Release
CShellExt::Release
CShellExt::GetCommandString
CShellExt::GetCommandString
CShellExt::GetCommandString
CShellExt::GetCommandString
CShellExt::QueryInterface {FC4801A3-2BA9-11CF-A229-00AA003D7352} IObjectWithSite
CShellExt::QueryInterface {79EAC9EE-BAF9-11CE-8C82-00AA004BA90B} IInternetSecurityManager
CShellExt::Release
CShellExt::~CShellExt

Explorer:
CShellExt::CShellExt
CShellExt::QueryInterface {000214E8-0000-0000-C000-000000000046} IShellExtInit
CShellExt::AddRef
CShellExt::AddRef
CShellExt::Release
CShellExt::QueryInterface {00000003-0000-0000-C000-000000000046} IMarshal
CShellExt::QueryInterface {0000001B-0000-0000-C000-000000000046} IdentityUnmarshal
CShellExt::QueryInterface {00000000-0000-0000-C000-000000000046} IUnknown
CShellExt::AddRef
CShellExt::AddRef
CShellExt::QueryInterface {00000018-0000-0000-C000-000000000046} IStdMarshalInfo
CShellExt::QueryInterface {00000019-0000-0000-C000-000000000046} IExternalConnection
CShellExt::QueryInterface {4C1E39E1-E3E3-4296-AA86-EC938D896E92} ?
CShellExt::Release
CShellExt::QueryInterface {000214E8-0000-0000-C000-000000000046} IShellExtInit
CShellExt::AddRef
CShellExt::Release
CShellExt::Release
CShellExt::Release
CShellExt::~CShellExt
Re[3]: проблема с shell extension
От: dIcEmAN  
Дата: 09.04.07 06:05
Оценка: 2 (1)
Здравствуйте, dkotlyarov, Вы писали:

D>

КД>>Добавь трассировку вызовов QueryInterface



D>Пункт меню успешно добавляется при вызове контекстного меню на рабочем столе, а при вызове из explorer-а — нет

D>Я определил последовательность вызовов методов CShellExt в случае с рабочим столом и с explorer-ом. Из explorer-а почему-то вообще не вызывается IShellExtInit::Initialize и не запрашивается интерфейс IContextMenu...

Решил поднять эту бородатую ветку потому что столкнулся с идентичной проблемой и не нашёл явного ответа. Дело в том что компонент неправильно зарегистрирован в реестре, не хватает ключа ThreadingModel=Apartment. Вот и всё решение.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.