Приветствия StackOverflowians,
Как обнаружено здесь , в Windows 7 имеется ошибка, из-за которой событие DISPID_BEFORENAVIGATE2 не запускается для экземпляров Windows Explorer.Это событие позволяет уведомлять расширения оболочки, когда навигация вот-вот произойдет, и (что наиболее важно для меня) имеет возможность отменить навигацию.Я искал обходной путь в течение довольно долгого времени, и я думаю, что нашел его.Но я хотел бы получить некоторые мнения о том, насколько это безопасно.
В последнее время я много играл с перехватом API и уже использую его, чтобы перехватить несколько функций для моего расширения.Я заметил, что в IShellBrowser есть функция , которая управляет навигацией.Сначала я думал, что вы не можете подключить что-то подобное, но прочитав о макете COM-объекта , я понял, что это возможно, просто выбрав правильный указатель функции из виртуальной таблицы любого активного экземпляра.,Конечно же, это работает как сон.После того, как хук установлен, все переходы во всех окнах Проводника проходят через мою функцию обхода, и я могу решить, отклонять ли их, основываясь на их целевом pidl.
Так что мой вопрос, есть ли причина, по которой я долженНЕ делать это?Я никогда не слышал о перехватах API, используемых для перехвата функций COM-объектов.Есть ли обстоятельства, которые бы не сработали?Это опасно?(По крайней мере, больше, чем обычные перехваты API)
Соответствующий код следует.Я использую MinHook , минималистичную библиотеку перехвата, которая использует проверенный метод батутных функций.
typedef HRESULT (WINAPI *BROWSEOBJECT)(IShellBrowser*, PCUIDLIST_RELATIVE, UINT);
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags);
BROWSEOBJECT fpBrowseObject = NULL;
BROWSEOBJECT ShellBrowser_BrowseObject = NULL;
bool Initialize() {
if(MH_Initialize() != MH_OK) {
return false;
}
// Get a reference to an existing IShellBrowser. Any instance will do.
// ShellBrowser enum code taken from The Old New Thing
IShellWindows *psw;
BOOL fFound = FALSE;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**)&psw))) {
VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK; V_I4(&v)++) {
IWebBrowserApp *pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
IServiceProvider *psp;
if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
IShellBrowser *psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,IID_IShellBrowser, (void**)&psb))) {
fFound = true;
// Grab the 11th entry in the VTable, which is BrowseObject
void** vtable = (*(void***)(psb));
ShellBrowser_BrowseObject = (BROWSEOBJECT)(vtable[11]);
psb->Release();
}
psp->Release();
}
pwba->Release();
}
pdisp->Release();
}
psw->Release();
}
if(fFound) {
if(MH_CreateHook(ShellBrowser_BrowseObject, &DetourBrowseObject, reinterpret_cast<void**>(&fpBrowseObject)) != MH_OK) {
return false;
}
if(MH_EnableHook(ShellBrowser_BrowseObject) != MH_OK) {
return false;
}
}
return true;
}
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags) {
if(NavigateIsOkay(pidl, wFlags)) {
return fpBrowseObject(_this, pidl, wFlags);
}
else {
return S_FALSE;
}
}