rabbitears
asked on
Help porting a few lines of c++ to C#
Basically, I need help porting a few lines of code from c++ to c#. Here's the basic idea.
1. Loop through every running instance of Internet Explorer on the current computer.
2. Get an IHTMLDocument2 from the HWND of each "Internet Explorer_Server" window.
3. Retrieve IHTMLDocument2.body.innerT ext.
Now, I've already done EVERYTHING except for number 3. And I'm really REALLY close to figuring it out, but I've spent SO much time trying to get it to work that I'm even closer to giving up... So I figured I'd just ask the pros here! :) It's really going to be a sweet piece of code if/when it can be made to work! In fact, I'm going to use it to make a VisualStudio.NET add-in that will shorten every ASP.NET build time by about 10 seconds! Well, technically it shortens the time BETWEEN builds, but when you're doing build after build after build... any time that can be saved is much appreciated.
As I said, all I'm really doing is porting c++ code to c#. Here are a few links that have helped me get this far. For anyone who is helping me out with this one, these links should DEFINITELY give you all the information you need to complete the code.
1. http://www.codeguru.com/internet/YahooChat_p2.html
This article shows EXACTLY how to retrive the text from an IHTMLDocument2 interface (#3 on the list above) in c++. This has the majority of the code we want to port.
2. http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q249232&
Here is a Microsoft article on "HOWTO: Get IHTMLDocument2 from a HWND". Again, this code is in c++
3. http://www.domaindlx.com/e_morcillo/scripts/tips/en/ie/iedom.asp
Here's where things get slightly interesting. This article is actually a port of the code in link 2 to VB! This was actually a pretty big help, as I don't think I could have made it this far without it! You'll see a few elements from the VB code that I ported to C# in my own code.
4. http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/document2/document2.asp
Here is the documentation for the IHTMLDocument2 Interface
5. http://msdn.microsoft.com/workshop/browser/mshtml/reference/reference.asp
Here's a link to the MSHTML reference
And finally, here is my code!
The main line in question is:
hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, iHTMLDocument2);
The problem seems to lie in how I prototype the ObjectFromLresult function (also included below) and the parameters that I pass to the function. Specifically, the second and third parameters. I feel as if I've tried every possible combination of IHTMLDocument, HTMLDocument, HTMLDocumentClass and IHtmlDocument2 that is possible. Sometimes the function will proceed, but the resultant object returned from the fourth parameter (HTMLDocument) is empty. The result is a NullReferenceException when you try to access thedoc.body.innerhtml.
The code below is a bit messy because I've been hacking on it all day, but I think that's the combination of parameters that should work best. The application is a VERY simple windows form application with a single listbox in it. The idea is to put the HTML content from each IE instance into a row in the listbox. I know that doesn't sound like a practical application, but that's really as far as I need help. The result, I assure you will be well worth it. Anyway, I've got everything working EXCEPT the part where you get the .innerText from the window and I've already discussed that situation.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Text;
using System.Runtime.InteropServ ices;
public delegate bool IECallBack(int hwnd, int lParam);
namespace Locaterr
{
/// <summary>
/// Summary description for Locaterr.
/// </summary>
///
public class Locaterr : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Cont ainer components = null;
static IntPtr listBoxHandle;// IntPtr is a class in System namespace
static IntPtr windowHandle;
static StringBuilder sb, sbc;
private System.Windows.Forms.ListB ox listBox1;
public Locaterr()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
listBoxHandle = listBox1.Handle;
EnumWindows (new IECallBack(Locaterr.EnumWi ndowCallBa ck), (int)listBoxHandle) ;
}
private static bool EnumWindowCallBack(int hwnd, int lParam)
{
windowHandle = (IntPtr)hwnd;
listBoxHandle = (IntPtr)lParam;
int foundWindow;
ListBox lb =(ListBox)ListBox.FromHand le(listBox Handle);
sb = new StringBuilder(1024);
sbc = new StringBuilder(256);
GetClassName(hwnd,sbc,sbc. Capacity);
//GetWindowText((int)windo wHandle, sb, sb.Capacity);
//String xMsg = sb+" "+sbc+" "+windowHandle;
if( sbc.Length > 0 )
{
if( sbc.ToString().Equals("IEF rame"))
{
foundWindow = FindWindowEx(hwnd, 0, "Shell DocObject View", "");
if (foundWindow != 0)
{
foundWindow = FindWindowEx(foundWindow, 0, "Internet Explorer_Server", "");
string content = GetHTMLContent(foundWindow );
lb.Items.Add(content);
}
}
}
return true;
}
public static string GetHTMLContent(int htmlWindow)
{
mshtml.HTMLDocumentClass htmlDocumentClass = new mshtml.HTMLDocumentClass() ;
mshtml.HTMLDocument htmlDocument = (mshtml.HTMLDocument)htmlD ocumentCla ss;
mshtml.IHTMLDocument2 iHTMLDocument2 = (mshtml.IHTMLDocument2)htm lDocumentC lass;
mshtml.IHTMLDocument iHTMLDocument = (mshtml.IHTMLDocument)html DocumentCl ass;
Guid guid = new Guid("626FC520-A41E-11cf-A 731-00A0C9 082637");
byte[] guidArray = guid.ToByteArray();
int foundWindow = htmlWindow;
string htmlContent = "";
UUID IID_IHTMLDocument = new UUID();
int lRes = 0;
int lMsg = 0;
int hr = 0;
if (foundWindow != 0)
{
// Register the message
lMsg = RegisterWindowMessage("WM_ HTML_GETOB JECT");
// Get the object
int result = SendMessageTimeout(htmlWin dow, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, ref lRes);
if (result != 0)
{
if (lRes > 0)
{
// Initialize the interface ID
IID_IHTMLDocument.Data1 = 0x626FC520;
IID_IHTMLDocument.Data2 = 0xA41E;
IID_IHTMLDocument.Data3 = 0x11CF;
IID_IHTMLDocument.Data4 = new byte[8];
IID_IHTMLDocument.Data4[0] = 0xA7;
IID_IHTMLDocument.Data4[1] = 0x31;
IID_IHTMLDocument.Data4[2] = 0x0;
IID_IHTMLDocument.Data4[3] = 0xA0;
IID_IHTMLDocument.Data4[4] = 0xC9;
IID_IHTMLDocument.Data4[5] = 0x8;
IID_IHTMLDocument.Data4[6] = 0x26;
IID_IHTMLDocument.Data4[7] = 0x37;
// Get the object from lRes
try
{
hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, iHTMLDocument2);
}
catch (Exception e)
{
MessageBox.Show("Did not get IHTMLDocument: " + e.Message);
}
try
{
mshtml.IHTMLDocument2 test1 = (mshtml.IHTMLDocument2)iHT MLDocument ;
mshtml.IHTMLDocument test2 = (mshtml.IHTMLDocument)iHTM LDocument;
mshtml.HTMLDocument test3 = (mshtml.HTMLDocument)iHTML Document;
string text = iHTMLDocument2.body.innerT ext;
}
catch (Exception e)
{
MessageBox.Show("Could not get inner text: " + e.Message);
}
}
}
}
return htmlContent;
}
[ StructLayout( LayoutKind.Sequential ) ]
public struct UUID
{
public long Data1;
public int Data2;
public int Data3;
[MarshalAs(System.Runtime. InteropSer vices.Unma nagedType. ByValArray , SizeConst=8)]
public byte[] Data4;
}
[DllImport("Oleacc.Dll")]
public static extern int ObjectFromLresult (long lResult, [MarshalAs(UnmanagedType.S truct)] UUID _riid, int wParam, mshtml.IHTMLDocument2 _ppvObject);
[DllImport("user32.dll")]
private static extern int FindWindowEx(int parentWindow, int childWindow, string _ClassName, string _WindowName);
[DllImport("user32.Dll")]
public static extern int EnumWindows(IECallBack x, int y);
[DllImport("user32.Dll")]
public static extern int EnumChildWindows(int parent, IECallBack x, int y);
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s, int nMaxCount);
[DllImport("User32.Dll")]
public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
[DllImport("User32.Dll")]
public static extern int RegisterWindowMessage(stri ng lpString );
[DllImport("User32.Dll")]
public static extern int SendMessageTimeout(int hWnd, int msg, int wParam, int _lParam, int fuFlags, int uTimeout, ref int _lpdwResult);
public const int SMTO_ABORTIFHUNG = 0x2;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listBox1 = new System.Windows.Forms.ListB ox();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.Dock = System.Windows.Forms.DockS tyle.Fill;
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(360, 277);
this.listBox1.TabIndex = 0;
//
// Locaterr
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(360, 285);
this.Controls.AddRange(new System.Windows.Forms.Contr ol[] {
this.listBox1});
this.Name = "Locaterr";
this.Text = "Locaterr";
this.ResumeLayout(false);
}
#endregion
}
}
1. Loop through every running instance of Internet Explorer on the current computer.
2. Get an IHTMLDocument2 from the HWND of each "Internet Explorer_Server" window.
3. Retrieve IHTMLDocument2.body.innerT
Now, I've already done EVERYTHING except for number 3. And I'm really REALLY close to figuring it out, but I've spent SO much time trying to get it to work that I'm even closer to giving up... So I figured I'd just ask the pros here! :) It's really going to be a sweet piece of code if/when it can be made to work! In fact, I'm going to use it to make a VisualStudio.NET add-in that will shorten every ASP.NET build time by about 10 seconds! Well, technically it shortens the time BETWEEN builds, but when you're doing build after build after build... any time that can be saved is much appreciated.
As I said, all I'm really doing is porting c++ code to c#. Here are a few links that have helped me get this far. For anyone who is helping me out with this one, these links should DEFINITELY give you all the information you need to complete the code.
1. http://www.codeguru.com/internet/YahooChat_p2.html
This article shows EXACTLY how to retrive the text from an IHTMLDocument2 interface (#3 on the list above) in c++. This has the majority of the code we want to port.
2. http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q249232&
Here is a Microsoft article on "HOWTO: Get IHTMLDocument2 from a HWND". Again, this code is in c++
3. http://www.domaindlx.com/e_morcillo/scripts/tips/en/ie/iedom.asp
Here's where things get slightly interesting. This article is actually a port of the code in link 2 to VB! This was actually a pretty big help, as I don't think I could have made it this far without it! You'll see a few elements from the VB code that I ported to C# in my own code.
4. http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/ifaces/document2/document2.asp
Here is the documentation for the IHTMLDocument2 Interface
5. http://msdn.microsoft.com/workshop/browser/mshtml/reference/reference.asp
Here's a link to the MSHTML reference
And finally, here is my code!
The main line in question is:
hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, iHTMLDocument2);
The problem seems to lie in how I prototype the ObjectFromLresult function (also included below) and the parameters that I pass to the function. Specifically, the second and third parameters. I feel as if I've tried every possible combination of IHTMLDocument, HTMLDocument, HTMLDocumentClass and IHtmlDocument2 that is possible. Sometimes the function will proceed, but the resultant object returned from the fourth parameter (HTMLDocument) is empty. The result is a NullReferenceException when you try to access thedoc.body.innerhtml.
The code below is a bit messy because I've been hacking on it all day, but I think that's the combination of parameters that should work best. The application is a VERY simple windows form application with a single listbox in it. The idea is to put the HTML content from each IE instance into a row in the listbox. I know that doesn't sound like a practical application, but that's really as far as I need help. The result, I assure you will be well worth it. Anyway, I've got everything working EXCEPT the part where you get the .innerText from the window and I've already discussed that situation.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Text;
using System.Runtime.InteropServ
public delegate bool IECallBack(int hwnd, int lParam);
namespace Locaterr
{
/// <summary>
/// Summary description for Locaterr.
/// </summary>
///
public class Locaterr : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Cont
static IntPtr listBoxHandle;// IntPtr is a class in System namespace
static IntPtr windowHandle;
static StringBuilder sb, sbc;
private System.Windows.Forms.ListB
public Locaterr()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
listBoxHandle = listBox1.Handle;
EnumWindows (new IECallBack(Locaterr.EnumWi
}
private static bool EnumWindowCallBack(int hwnd, int lParam)
{
windowHandle = (IntPtr)hwnd;
listBoxHandle = (IntPtr)lParam;
int foundWindow;
ListBox lb =(ListBox)ListBox.FromHand
sb = new StringBuilder(1024);
sbc = new StringBuilder(256);
GetClassName(hwnd,sbc,sbc.
//GetWindowText((int)windo
//String xMsg = sb+" "+sbc+" "+windowHandle;
if( sbc.Length > 0 )
{
if( sbc.ToString().Equals("IEF
{
foundWindow = FindWindowEx(hwnd, 0, "Shell DocObject View", "");
if (foundWindow != 0)
{
foundWindow = FindWindowEx(foundWindow, 0, "Internet Explorer_Server", "");
string content = GetHTMLContent(foundWindow
lb.Items.Add(content);
}
}
}
return true;
}
public static string GetHTMLContent(int htmlWindow)
{
mshtml.HTMLDocumentClass htmlDocumentClass = new mshtml.HTMLDocumentClass()
mshtml.HTMLDocument htmlDocument = (mshtml.HTMLDocument)htmlD
mshtml.IHTMLDocument2 iHTMLDocument2 = (mshtml.IHTMLDocument2)htm
mshtml.IHTMLDocument iHTMLDocument = (mshtml.IHTMLDocument)html
Guid guid = new Guid("626FC520-A41E-11cf-A
byte[] guidArray = guid.ToByteArray();
int foundWindow = htmlWindow;
string htmlContent = "";
UUID IID_IHTMLDocument = new UUID();
int lRes = 0;
int lMsg = 0;
int hr = 0;
if (foundWindow != 0)
{
// Register the message
lMsg = RegisterWindowMessage("WM_
// Get the object
int result = SendMessageTimeout(htmlWin
if (result != 0)
{
if (lRes > 0)
{
// Initialize the interface ID
IID_IHTMLDocument.Data1 = 0x626FC520;
IID_IHTMLDocument.Data2 = 0xA41E;
IID_IHTMLDocument.Data3 = 0x11CF;
IID_IHTMLDocument.Data4 = new byte[8];
IID_IHTMLDocument.Data4[0]
IID_IHTMLDocument.Data4[1]
IID_IHTMLDocument.Data4[2]
IID_IHTMLDocument.Data4[3]
IID_IHTMLDocument.Data4[4]
IID_IHTMLDocument.Data4[5]
IID_IHTMLDocument.Data4[6]
IID_IHTMLDocument.Data4[7]
// Get the object from lRes
try
{
hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, iHTMLDocument2);
}
catch (Exception e)
{
MessageBox.Show("Did not get IHTMLDocument: " + e.Message);
}
try
{
mshtml.IHTMLDocument2 test1 = (mshtml.IHTMLDocument2)iHT
mshtml.IHTMLDocument test2 = (mshtml.IHTMLDocument)iHTM
mshtml.HTMLDocument test3 = (mshtml.HTMLDocument)iHTML
string text = iHTMLDocument2.body.innerT
}
catch (Exception e)
{
MessageBox.Show("Could not get inner text: " + e.Message);
}
}
}
}
return htmlContent;
}
[ StructLayout( LayoutKind.Sequential ) ]
public struct UUID
{
public long Data1;
public int Data2;
public int Data3;
[MarshalAs(System.Runtime.
public byte[] Data4;
}
[DllImport("Oleacc.Dll")]
public static extern int ObjectFromLresult (long lResult, [MarshalAs(UnmanagedType.S
[DllImport("user32.dll")]
private static extern int FindWindowEx(int parentWindow, int childWindow, string _ClassName, string _WindowName);
[DllImport("user32.Dll")]
public static extern int EnumWindows(IECallBack x, int y);
[DllImport("user32.Dll")]
public static extern int EnumChildWindows(int parent, IECallBack x, int y);
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s, int nMaxCount);
[DllImport("User32.Dll")]
public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
[DllImport("User32.Dll")]
public static extern int RegisterWindowMessage(stri
[DllImport("User32.Dll")]
public static extern int SendMessageTimeout(int hWnd, int msg, int wParam, int _lParam, int fuFlags, int uTimeout, ref int _lpdwResult);
public const int SMTO_ABORTIFHUNG = 0x2;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listBox1 = new System.Windows.Forms.ListB
this.SuspendLayout();
//
// listBox1
//
this.listBox1.Dock = System.Windows.Forms.DockS
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(360, 277);
this.listBox1.TabIndex = 0;
//
// Locaterr
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(360, 285);
this.Controls.AddRange(new
this.listBox1});
this.Name = "Locaterr";
this.Text = "Locaterr";
this.ResumeLayout(false);
}
#endregion
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
rabbitears, Are you listening with those floppy things? -- Dan
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:
Accept a comment by DanRollins
Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
TheAvenger
EE Cleanup Volunteer
I will leave a recommendation in the Cleanup topic area that this question is:
Accept a comment by DanRollins
Please leave any comments here within the next seven days.
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
TheAvenger
EE Cleanup Volunteer
Please add a comment. You must keep in communication if you want an Expert to continue working on your problem.
-- Dan