Одразу маленька відмазка: те, що надалі описане мені потрібно було виключно по роботі. Сам я IE не користуюсь – лише Оперою та Файрфоксом 😉
Не дивлячись на те, що сабжева задача здається вельми і вельми тривіальною насправді все не атк просто. Мається на увазі URL, по якому переходить браузер, якщо ви введети якусь маячню в Location Bar (напр. набір слів, або неіснуючий домен). Точніше велику проблему це становить для IE6. Для Internet Explorer 7 все вирішується просто – URL для закачки міняється правкою ключа реєстру:
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchScopes\{0633EE93-D776-472f-A0FF-E1416B8B2E3A}\URL
Міняємо прописаний там майкрософтівський Live search на щось типу:
http://www.google.com.ua/search?hl=uk&q={searchTerms}&meta=
де {searchTerms} – макрос, на місце якого підставляється введені в рядку браузера лексеми. І все ОК. А от в IE6 такого ключа нема. І там все робиться через дупу. Саме цей романтичний шлях і буде далі описано…
Для визначення URL для підстановки в Address bar в разі, коли IE не може знайти протокол по якому потрібно працювати (ви не вказали його, а дреса не містить ніяких підказок, напр. у вигляді префікса “www.”) викликається COM-об’єкт, що реалізує інтерфейс IURLSearchHook. Цей інтерфейс має лише одну член-функцію: Translate. В комплекті з IE6 йде власна реалізація цього інтерфейсу, яка відкриває сторінку auto.search.msn.com. CLSID об’єкта, який відповідатиме за постачання URL прописано в ключі HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\URLSearchHooks
. По замовучуванню використовується об’єкт з CLSID {CFBFAE00-17A6-11D0-99CB-00C04FD64497}
. Для того, щоб встановити власний URL для пошуку за замовчуванням нам потрібно замінити його своєю реалізацію.
Для цього створюємо звичанйий проект ATL:
Параметри залишаємо без змін. Далі в щойноствореному проекті через Class Wizard додаємо ATL Simple Object – клас, який і буде реалізацією інтерфейсу IURLSearchHook.
Даємо цьому класу якесь ім’я. Вкладку “Options” можна не чіпати і залишити все по дефолту.
Class Wizard зробив для нас практично всю брудну роботу і тепер можна, власне, дописувати необхідні дані.
Файл з описанням класу (в нашому прикладі Searcher.h) доводимо до наступного вигляду:
// Searcher.h : Declaration of the CSearcher
#pragma once
#include "resource.h" // main symbols
#include <..\PlatformSDK\include\comdef.h>
#include <shlobj.h>
// ISearcher
[ object, uuid("A548953B-21A1-490F-A189-0F9FD714BDE2"),
dual, helpstring("ISearcher Interface"), pointer_default(unique) ]
__interface ISearcher : IDispatch { };
// CSearcher
[ coclass, threading("apartment"), vi_progid("IESearchHook.Searcher"),
progid("IESearchHook.Searcher.1"), version(1.0),
uuid("94D618D6-E6E7-4EE9-B1B7-24C0B2327853"), helpstring("Searcher Class") ]
class ATL_NO_VTABLE CSearcher :
public ISearcher,
public IURLSearchHook
{
public:
CSearcher() {}
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CSearcher)
COM_INTERFACE_ENTRY(ISearcher)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IURLSearchHook)
END_COM_MAP()
HRESULT FinalConstruct() { return S_OK; }
void FinalRelease() {}
public:
STDMETHODIMP Translate(LPWSTR lpwszSearchURL, DWORD cchBufferSize)
{
LPWSTR wszURL = new WCHAR[cchBufferSize];
::LoadStringW(_AtlBaseModule.GetModuleInstance(), IDS_URL404, wszURL, cchBufferSize);
wcsncat(wszURL, lpwszSearchURL, cchBufferSize);
ZeroMemory(lpwszSearchURL, wcslen(wszURL));
wcsncpy( lpwszSearchURL, wszURL, cchBufferSize);
delete [] wszURL;
return S_OK;
}
};
Далі створюємо ресурс в String table з ідентифікатором IDS_URL404 і змістом типу: http://www.google.com/search?q= (це пошук по гуглю) і збираємо продукт. Реєстрацію COM-об’єкта Visual Studio зробить за нас, але для того, щоб зареєструвати цю dll-бібліотеку на іншому компі потрібно буде виконати команду:
regsvr32 IESearchHook.dll
До речі, по коду ще прошу звернути увагу на рядок:
#include <..\PlatformSDK\include\comdef.h>
Справа в тому, що принаймні в Visual Studio .NET (2003) є два файли comdef.h і в одному з них не прописано GUID для IURLSearchHook. І тоді при компіляції в рядку:
COM_INTERFACE_ENTRY(IURLSearchHook)
може видаватись помилка типу:
d:\Work\Other\IESearchHook\Searcher.h(49) : error C2787: 'IURLSearchHook' : no GUID has been associated with this object
Тому для того, щоб використовувати нормальний comdef.h пересвідчіться, що використовується саме той, який лежить в:
PATH_TO_VISUAL_STUDIO\Vc7\PlatformSDK\Include\
Ну і нарешті останній крок – це підстановка нашого COM-об’єкту замість експлорерівського. Для цього в ключі
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\URLSearchHooks
видаляємо параметр, ім’я якого є CLSID поточного об’єкту, що видає рядок пошуку і створюємо параметр з іменем, рівним CLSID нашого об’єкту, обгонувши його в фігурні дужки. Для прикладу вище – це буде “{94D618D6-E6E7-4EE9-B1B7-24C0B2327853}”.
От і все. Запускаємо Internet Explorer і насолоджуємось пошуком в Google замість Live Search 😉 Цей спосіб випробувано для Internet Explorer версій 6 та 7. По ідеї має працювати починаючи з 4-го, але це не перевірялося.
Звісно, для реальної роботи функцію Translate треба буде дещо ускладнити, але то вже більш тривіальна справа.
За реалізацію цього завдання вчасно я мушу подякувати наявності наступних двох ресурсів:
- Google Answers: Change Autosearch URL in IE6. Але спосіб описаний тут не зовсім працює 😉 Одна з помилок – це якраз описаний вище прикол з comdef.h
- Якийсь китайський ресурс. Там добре, що була купа скрінів та багато коду і я інтуітивно здогадався в цій купі ієрогліфів в чому була лажа 🙂