2013-06-04 2 views
1

У меня есть приложение .NET .NET WinForms (с использованием MSHTML 7), которое запускает новые и подключается к существующим экземплярам IE 10. Он выполняет итерацию по всем изображениям и загружает их для управления. Этот подход требует много времени и избыточности, поскольку изображение уже загружено IE.Кастинг mshtml.IHTMLImgElement в mshtml.IHTMLElementRender сбой с E_NOINTERFACE

Я искал повсюду, и только несколько форумов обсуждают тему, но все могут отбрасывать объекты mshtml.IHTMLImgElement в mshtml.IHTMLElementRender (хотя в коде на C++).

Unable to cast COM object of type 'mshtml.HTMLImgClass' to interface type 'mshtml.IHTMLElementRender'. 
This operation failed because the QueryInterface call on the COM component for the interface with IID '{3050F669-98B5-11CF-BB82-00AA00BDCE0B}' failed due to the following error: 
No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)). 

Целью, конечно же, является получение доступа к полному изображению, поэтому приветствуются альтернативные подходы. Вот код, вызывающий исключение выше.

public static void Main (string [] args) 
{ 
    mshtml.HTMLDocument document = null; 
    SHDocVw.InternetExplorer explorer = null; 
    System.IntPtr hdc = System.IntPtr.Zero; 
    mshtml.IHTMLElementRender render = null; 
    mshtml._RemotableHandle handle = default(mshtml._RemotableHandle); 

    try 
    { 
     explorer = new SHDocVw.InternetExplorer(); 
     explorer.Visible = true; 

     try 
     { 
      explorer.Navigate("http://www.google.com/ncr"); 

      while (explorer.Busy) 
      { 
       // Striped events for SO example. 
       System.Threading.Thread.Sleep(100); 
      } 

      document = (mshtml.HTMLDocument) explorer.Document; 

      foreach (mshtml.IHTMLImgElement image in document.images) 
      { 
       Console.WriteLine(); 

       if ((image.width > 0) && (image.height > 0)) 
       { 
        // The following [if] will return false if uncommented. 
        //if (image.GetType().GetInterfaces().ToList().Contains(typeof(mshtml.IHTMLElementRender))) 
        { 
         using (Bitmap bitmap = new Bitmap(image.width, image.height)) 
         { 
          using (Graphics graphics = Graphics.FromImage(bitmap)) 
          { 
           hdc = graphics.GetHdc(); 
           handle.fContext = hdc.ToInt32(); 
           render = (mshtml.IHTMLElementRender) image; // Causes the exception. 
           //handle = (mshtml._RemotableHandle) Marshal.PtrToStructure(hdc, typeof(mshtml._RemotableHandle)); 
           render.DrawToDC(ref handle); 
           graphics.ReleaseHdc(hdc); 

           // Process image here. 

           Console.Write("Press any key to continue..."); 
           Console.ReadKey(); 
          } 
         } 
        } 
       } 
      } 
     } 
     catch (System.Exception e) 
     { 
      Console.WriteLine(e.Message); 
      Console.WriteLine("Stack Trace: " + e.StackTrace); 
     } 

     explorer.Quit(); 
    } 
    catch (System.Exception e) 
    { 
     Console.WriteLine(e.Message); 
     Console.WriteLine("Stack Trace: " + e.StackTrace); 
    } 
    finally 
    { 
    } 

#if (DEBUG) 
     Console.WriteLine(); 
     Console.Write("Press any key to continue..."); 
     Console.ReadKey(); 
#endif 
} 

Некоторые ссылки я прошли через без толку:

ответ

2

Вы можете легко увидеть корень проблемы с Regedit.exe. Для того, чтобы интерфейс мог объединить Гранд-Каньон между границами процесса, ему нужен код, который реализует прокси-сервер и заглушку для интерфейса. Код, который знает, как сериализовать аргументы метода интерфейса в пакет RPC, который может быть передан из одного процесса в другой.

COM обнаруживает этот код, просматривая реестр. Вы также можете использовать Regedit.exe, перейдите на HKCR \ Interfaces и прокрутите вниз, чтобы соответствовать guid. Вы увидите лот {guids}, который выглядит как {305xxxx-98B5-11CF-BB82-00AA00BDCE0B}. Да, Microsoft обманывает свои концы, проще для отладки, у IE их довольно много. Они указывают на стандартный маршаллер и включают в себя руководство по типу библиотеки, которое описывает интерфейс.

Но вы будете не найти {3050F669-98B5-11CF-BB82-00AA00BDCE0B}. В общем, что сообщение об исключении говорит вам, оно не может найти способ маршалирования указателя интерфейса. Таинственный код ошибки E_NOINTERFACE является результатом того, что альтернативный подход не работает, не получив запрос для IMarshal.

Это немного похоже на то, что они «забыли» и «они не могут заставить его работать». Этот человек сильно склоняется к «слишком тяжело, чтобы заставить его работать». Сериализация интерфейса визуализации слишком сложна, слишком много зависимостей от видеооборудования, которое, конечно же, не совпадает между одной машиной и другой. Или даже на одной машине необходимость правильной инициализации графического конвейера перед любыми вызовами метода слишком сложна.

Это то, о чем останавливается доллар, вы не можете сделать эту работу. Вам нужно будет сделать это изображение самостоятельно, а не просто сделать. Извините, пожалуйста, не стреляйте в посланника.

+0

Crap. Один из вариантов - использовать IViewObject, у которого есть свои собственные причуды. Правильно ли я понимаю, что это невозможно сделать через COM Interop из-за причин, о которых вы говорили, но может быть сделано с помощью собственного кода? Если да, то быстрая библиотека DLL для рендеринга и сохранения изображения была бы предпочтительнее для IViewObject. –

+0

Я определенно собираюсь ограничить свой ответ на исходный вопрос и объяснить, почему это идет не так. То, что вы собираетесь об этом, порождает «удачу!». комментарий. –

+0

Я возьму это как да и сделаю снимок: P. Благодарим вас за отличное объяснение и часы, которые он сохранит с будущими проблемами, связанными с интерфейсами com. –

 Смежные вопросы

  • Нет связанных вопросов^_^