Получая URL и HTML через BHO, SetSite генерирует исключение

#c# #com #interop #bho

#c# #com #взаимодействие #bho

Вопрос:

Я следовал руководству по адресу:http://www.15seconds.com/issue/040331.htm для создания BHO, однако, у меня, похоже, не работает, у меня есть код наблюдателя из examble, где она создает фактический BHO, но когда я пытаюсь ввести тип в моем SetSite, он останавливается, я подозреваю, что получаю исключение.

Это мой пример кода, просто удалил все это, поэтому вместо этого я получаю окно сообщения.

 [ClassInterfaceAttribute(ClassInterfaceType.None)]
    [GuidAttribute("0CD00297-9A19-4698-AEF1-682FBE9FE88D")]
    [ProgIdAttribute("Observer.BrowserMonitor")]
    public class BrowserMonitor: IObserver, IObjectWithSite
    {

        // HRESULT values used
        const int E_FAIL = unchecked((int)0x80004005);
        const int E_NOINTERFACE = unchecked((int)0x80004002);

        public BrowserMonitor()
        {

        }


        protected SHDocVw.IWebBrowser2 m_pIWebBrowser2; // the browser class object

        public void SetSite(object pUnkSite)
        {
            System.Windows.Forms.MessageBox.Show(pUnkSite.ToString());
            if (pUnkSite != null)
            {
                m_pIWebBrowser2 = pUnkSite as SHDocVw.IWebBrowser2;
            }
        }

        public void GetSite(ref System.Guid riid, out object ppvSite)
        {            
            System.Windows.Forms.MessageBox.Show("GetSite");
            ppvSite = null;
        }

        protected void DocumentComplete(object pDisp, ref object URL)
        {            
            System.Windows.Forms.MessageBox.Show("DocumentComplete");

        }

        protected bool ServiceEnabled()
        {
            return true;
        }

        protected void Release()
        {
            System.Windows.Forms.MessageBox.Show("Release");
        }

        protected void BeforeNavigate2(object pDisp, ref object url, ref object Flags, ref object TargetFrameName, 
            ref object PostData, ref object Headers, ref bool Cancel)
        {
            System.Windows.Forms.MessageBox.Show("BeforeNavigate2");
        }

        protected void OnQuit() 
        {
            try
            {
                System.Windows.Forms.MessageBox.Show("OnQuit");
            }
            catch{}
        }

        protected void NavigateComplete2(object pDisp, ref object URL)
        {
            System.Windows.Forms.MessageBox.Show("NavigationComplete2");            
        }
  

Моя проблема в моем методе SetSite, как мне выполнить типизацию в браузере любого типа? Если я запущу этот пример в том виде, в каком он есть сейчас, я получу только окно сообщения «GetSite», если я удалю предложение if в SetSite, я также получу SetSite. Кто-нибудь знает, как это сделать?

Комментарии:

1. если я удалю «if», оставив только messagebox, он покажет messagebox. Если я оставлю там структуру «if», я даже не получу всплывающее окно messagebox

Ответ №1:

  1. (Не имеет значения для ответа) Вам действительно не следует писать BHO на C #. Да, это можно сделать, но это не очень хорошая идея. Даже с SxS в .NET 4; стоимость инициализации среды CLR для каждой открытой вкладки довольно высока. (Если вы настаиваете, то вы должны, по крайней мере, использовать .NET 4).

  2. Методы Get / Set site должны возвращать значение int в соответствии с документацией для IObjectWithSite . Ваше объявление интерфейса неверно.

  3. Ваша GetSite реализация должна выглядеть примерно так, как только вы исправите интерфейс:

     public int GetSite(ref Guid riid, out IntPtr ppvSite)
    {
        var pUnk = Marshal.GetIUnknownForObject(_pUnkSite);
        try
        {
            return Marshal.QueryInterface(pUnk, ref riid, out ppvSite);
        }
        finally
        {
            Marshal.Release(pUnk);
        }
    }
      

    В этом случае _pUnkSite это объект, который вам был предоставлен в SetSite . Так SetSite будет выглядеть примерно так:

     private object _pUnkSite;
    public int SetSite(object pUnkSite)
    {
        _pUnkSite = pUnkSite;
        //Cast pUnkSite to `IWebBrowser2` here and attach events.
        return 0;
    }
      

    Как только вы, наконец, разберетесь с некоторыми шаблонными кодами, вы можете использовать свой pUnkSite для чего-то вроде IWebBrowser2 для работы с DOM.

  4. <shamelessplug> Я знаю, что написание C # BHO — плохая идея, потому что я уже делал это. Здесь у меня есть шаблонный проект на GitHub.</shamelessplug>

Комментарии:

1. но не это ли SetSite, которое я ищу, для преобразования в веб-браузер для подключения к событиям навигации. Как я читал tuts, GetSite вызывается после его загрузки с целью освобождения в случае необходимости?

2. @H4mm3rHead Ваш интерфейс C # должен соответствовать определению COM IDL. .NET допустит ошибки сортировки, если что-то не выстроится правильно.

3. Просто изменил оба метода на int и заставил реализацию возвращать 0 (ноль) — это привело к зависанию моего iExplorer, и ничего не ответило, до этого изменения я получил свои ящики сообщений

4. Новая версия: просмотрел ваш tut, тот, за которым я следил, не использовал [PreserveSig] в интерфейсе, теперь я делаю и изменил методы, чтобы возвращать int, все работает (с возвращаемыми типами), и я получаю свой messagebox — по-прежнему нет приведения типов

5. @H4mm3rHead GetSite не должен возвращать ноль. Смотрите в моем обновленном примере кода.