none
C# and Windows 7 conflict

    Question

  • Hi,

    I am not sure if this must be in a Windows forum or here, as it cuts both ways..

    I have been using the following code with XP SP3 - 32Bit with no problems

    IEnumerable<dynamic> FindAllIE()
            {
                var t = Type.GetTypeFromProgID("Shell.Application");
                dynamic o = Activator.CreateInstance(t);
                try
                {
                    var ws = o.Windows();
                    for (int i = 0; i < ws.Count; i++)
                    {
                        var ie = ws.Item(i);
                        if (ie != null && System.IO.Path.GetFileName((string)ie.FullName) == "IEXPLORE.EXE")
                            yield return ie;
                    }
                }
                finally
                {
                    Marshal.FinalReleaseComObject(o);
                }
            }

    And it could find the IE window with no problems, BUT now after we took the next step to Windows 7 64Bit , The code above is not working....
    Could this be abstract windows problem or a code problem??? AND What shall I do to fix the problem???
    And this is the first problem...

    The second one is as follows ..

    I have used the following line of code to get the text inside a web page :

    IE_Window_Text = (string)ie.Document.body.innerText + Environment.NewLine;

    Now as the web page layout changed , and it is now using Frames inside the webpage, the line above is not able to catch the text which we need as it is now placed in a Frame, and it instead catches the text of the webpage without the contents of the Frames,,,

    How can I get the contents inside the frame to get my App up and running again??

    Thanks in advance for any help,, and sorry for bothering you all with such an old outdated problems...

    Friday, March 02, 2012 3:05 PM

Answers

  • namespace IELibrary
    {
      using System;
      using System.Linq;

      public static class ShellWindowWrapper
      {
        public static mshtml.HTMLDocument GetHTMLDocumentFromHwnd(IntPtr hwnd)
        {
          if (hwnd == IntPtr.Zero)
            return null;

          var wbSearched = new SHDocVw.ShellWindowsClass()
            .Cast<SHDocVw.WebBrowser>()
            .Where(wb => wb.HWND == hwnd.ToInt32())
            .SingleOrDefault();

          if (null == wbSearched)
            return null;

          if (!(wbSearched.Document is mshtml.HTMLDocument))
            return null;

          return (mshtml.HTMLDocument)wbSearched.Document;
        }
      }
    }

    JP Cowboy Coders Unite!

    Saturday, March 03, 2012 3:21 AM
  • This code works and shows you how to get to the frames collection...

    public void FindAllIE(){
        var t = Type.GetTypeFromProgID("Shell.Application");  
        dynamic o = Activator.CreateInstance(t);
        try {   
            var ws = o.Windows();
            for (int i = 0; i < ws.Count; i++){  
                var ie = ws.Item(i);
                if (ie != null && System.IO.Path.GetFileName((string)ie.FullName) == "iexplore.exe");
                var doc2 = (mshtml.IHTMLDocument2)ie.document;
                mshtml.IHTMLFramesCollection2 frames2 = doc2.frames;
                for (int j = 0; j < frames2.length;j++ )
                {
                    var thing = frames2.item(i);                      
    
                }
                }
            }catch(Exception iox){
                        
            }           
            finally{                
                Marshal.FinalReleaseComObject(o);            
            }
    }


    JP Cowboy Coders Unite!

    Tuesday, March 06, 2012 2:23 PM
  • Note you will have to add a reference to MSHTML via the COM classes to your project.   I like your solution becuase it totally bypasses having to work with hwnd pointers.   The only thing I don't care for in this style of programming above is that everything that comes back is a COM_OBJECT... Therefore you have to infer what the type is just to grab a method or property or two...  I did this first by attempting to do a GetType().UnderlyingSystemType.Name  which told me it was a COM_OBJECT.  I then was able to luckily guess that the object type of IE had a Document property which based on past experience was a MSHTML.IHTMLDOCUMENT type which could be case into MSHTML.ITHTMLDOCUMENT2 object.

    From there it is Welcome to MSHTML world!

    Good Luck!

    JP Cowboy Coders Unite!



    Tuesday, March 06, 2012 2:25 PM
  • Why do you need the process given a handle.  The Process.GetProcesses() method gives you all the running processes.  From there you have access to the filename and the main window (if any) - barring any security issues which you'll have to handle anyway.  I don't understand why you're trying to make this soo much harder than it needs to be.  You don't need to P/Invoke to get the process filename.

    Michael Taylor - 3/3/2012
    http://msmvps.com/blogs/p3net

    Saturday, March 03, 2012 9:30 PM
    Moderator
  • Filenames are not case sensitive in Windows.  To properly compare filenames use String.Compare(file1, file2, StringComparison.OrdinalIgnoreCase) == 0  Technically you could use case insensitive but ordinal is preferable.

    Michael Taylor - 3/4/2012
    http://msmvps.com/blogs/p3net

    Sunday, March 04, 2012 9:49 PM
    Moderator

All replies

  • For the first problem I don't understand why you have all that code.  You're getting access to the shell and then enumerating through looking for open IE windows.  Why don't you just use Process.GetProcesses() to get all the running processes?  Once you find an instance of IE (note that each tab runs as a subprocess) then you can get the associated window. 

    I suspect your crash is caused by the fact that security permissions do not allow you to view information about processes (or windows) that you don't own.  Hence during your enumeration the call will fail.  Ironically I believe you can view the process name but not the full name.  Irrelevant you'll need to wrap a try-catch around each call to the process data and handle/ignore the security exception.

    The second question is unrelated so I can't help you there.

    Michael Taylor - 3/2/2012
    http://msmvps.com/blogs/p3net

    Friday, March 02, 2012 3:51 PM
    Moderator
  • For the first problem, put your code into debug and tell us what you see in var ie...

    For the second problem you are correct you have to first get the proper frame which is in a collection.  Question how are you getting the Document, show that code.  Reason: If you are doing it natively you will have to use MSHTML to get the frame collection, if you application is hosting the System.Window.Forms.Webbrowser then that's done a bit differently.


    JP Cowboy Coders Unite!

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:23 PM
    • Unproposed as answer by Martin Rasch Monday, March 12, 2012 2:42 AM
    Friday, March 02, 2012 3:52 PM
  • Hi,
    So many thanks for you both for replies.

    As for the first problem , the var 'ie' gets null in each iteration ,, odd enough for me..
    And as for the second question I have my program runnig an an IE window open that has the webpage with FRAMEs in it.
    My code may be simple in a "stupid" way I think, as I am using the following line of code o get the text of the webpage that I found on the IE ::

    =======================================================
    Here I am supposed to get the IE Window
    =======================================================

    IEnumerable<dynamic> FindAllIE()
            {
                var t = Type.GetTypeFromProgID("Shell.Application");
                dynamic o = Activator.CreateInstance(t);
                try
                {
                    var ws = o.Windows();
                    for (int i = 0; i < ws.Count; i++)
                    {
                        var ie = ws.Item(i);
                        if (ie != null && System.IO.Path.GetFileName((string)ie.FullName) == "IEXPLORE.EXE")
                            yield return ie;
                    }
                }
                finally
                {
                    Marshal.FinalReleaseComObject(o);
                }
    }
    ===========================================================

    *****************************************************************
    and here I am getting the text in the webpage::
    *****************************************************************
    private void FindIEWindows()
            {
                foreach (var ie in FindAllIE())
                {
                   IE_Window_Text = (string)ie.Document.body.innerText + Environment.NewLine;
                }
            }
    *****************************************************************

    So, if we simply want to get the text inside One of the Frames inside the webpage,,, how can this be done??

    By the way,,

    In my Application I have tried to use the System.Window.Forms.Webbrowser and it failed due to security measures that made the

    server refuse the connection to it.

    Hope I am clear enough and so many thanks for replies...


    • Edited by Not_An_Expert Friday, March 02, 2012 4:31 PM
    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:24 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:18 PM
    • Proposed as answer by Martin Rasch Monday, March 12, 2012 2:42 AM
    • Unproposed as answer by MarcDModerator Monday, March 12, 2012 2:44 AM
    Friday, March 02, 2012 4:11 PM
  • So I think I am not clear enough as I thought,.. Sorrrrry.

    Please let me know what portion of code exactly should I show??

    And bare with me as I re-ask the same question >>

    How can we get the contents of a SPECIFIC FRAME inside a webpage opened using IE ,,, using a c# application??

    Thanks again for any help... and again sorry for bothering you all.

    Friday, March 02, 2012 9:36 PM
  • You can't do anything if you don't have addressibility to the webbrowser.  I am unfamilair with your approach but did see it out there on the internet.  If you host a browser in your own application that's a different story.

    JP Cowboy Coders Unite!

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:24 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:18 PM
    Saturday, March 03, 2012 3:16 AM
  • namespace IELibrary
    {
      using System;
      using System.Linq;

      public static class ShellWindowWrapper
      {
        public static mshtml.HTMLDocument GetHTMLDocumentFromHwnd(IntPtr hwnd)
        {
          if (hwnd == IntPtr.Zero)
            return null;

          var wbSearched = new SHDocVw.ShellWindowsClass()
            .Cast<SHDocVw.WebBrowser>()
            .Where(wb => wb.HWND == hwnd.ToInt32())
            .SingleOrDefault();

          if (null == wbSearched)
            return null;

          if (!(wbSearched.Document is mshtml.HTMLDocument))
            return null;

          return (mshtml.HTMLDocument)wbSearched.Document;
        }
      }
    }

    JP Cowboy Coders Unite!

    Saturday, March 03, 2012 3:21 AM
  • The code above takes a HWND point to instanciate an IE based Webbrowser.  It returns an HTML document that will allow you to get to the proper frame. But before you can do that you have to get all PROCESSes on the system, and find the HWND to IE instances.  Do that first and then I'll show you how to traverse the HTMLDOCUMENT to find the frame.

    JP Cowboy Coders Unite!

    Saturday, March 03, 2012 3:23 AM
  • Thanks Mr. Javaman II,,, and sorry for being late,,, had a long power cut.

    As for getting all PROCESSes on the system I think it may be something like this:: correct me if not, please::

    foreach(Process p in Process.GetProcesses()) 
    { 
          Console.WriteLine(p.ProcessName); 
    } 
    Console.ReadKey();

    Or maybe store them in an array :: 

    Process[] theProcesses = Process.GetProcesses();

    ------------

    As for the second section , I think I must admitt it again, as I am Not_An_Expert,,, it is hard for me to figure it out,, The only thing I know is something like the following:    "Shame on me!!!!"

    int myHandle = this.Handle.ToInt32();

    BUT I have came on some articles that may be related, but I got lost in between , below are the links:

    http://stackoverflow.com/questions/3924812/how-can-i-select-a-ie-tab-from-its-handle

    http://www.codeproject.com/Articles/2052/Capturing-the-Running-IE-Instances-in-C

    http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/16bf995d-6bab-40b5-a7ae-c844b7f0d51f

    http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/59b7c865-ccbe-463c-a0b8-e8e55b9bed2e/

    http://stackoverflow.com/questions/4768689/c-sharp-get-path-filename-by-handle-hwnd-32-and-64bit

    http://stackoverflow.com/questions/1982699/get-hwnd-of-containing-ie-window-from-toolbar

    http://msdn.microsoft.com/en-us/library/aa752126(VS.85).aspx

    Please point me to right direction and so many thanks, you have been so helpfull so far

    Saturday, March 03, 2012 9:11 AM
  • The following code is used to get path/filename by handle, is it what we are talking about and how should we make use of it in our problem,,, if it is what we need ?

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId);
        public static string GetProcessPath(IntPtr hwnd)
        {
            uint pid = 0;
            GetWindowThreadProcessId(hwnd, out pid);
            Process proc = Process.GetProcessById((int)pid);
            return proc.MainModule.FileName.ToString();
        }

    Thanks for help...
    Saturday, March 03, 2012 8:32 PM
  • Why do you need the process given a handle.  The Process.GetProcesses() method gives you all the running processes.  From there you have access to the filename and the main window (if any) - barring any security issues which you'll have to handle anyway.  I don't understand why you're trying to make this soo much harder than it needs to be.  You don't need to P/Invoke to get the process filename.

    Michael Taylor - 3/3/2012
    http://msmvps.com/blogs/p3net

    Saturday, March 03, 2012 9:30 PM
    Moderator
  • I got lost in between articles untill I lost track totally.

    All I need is a way to copy the text inside a FRAME in a webpage... but i seems to be so much harder than I thought.

    I have tried every thing I knew already but obviously it failed, I can't retrive the actual contents of the FRAME..

    Any help??

    Thanks for response,

    Saturday, March 03, 2012 9:38 PM
  • So, it is really that hard. I figured it would be so ..
    Should I look for another way to copy the contents of a FRAME in the webpage, or this is not do-able at all??!!
    Thanks for all the help..
    Sunday, March 04, 2012 2:57 PM
  • .

    Sunday, March 04, 2012 9:26 PM
  • hi Not_An_Expert,

    I think the problem is it is somehow casesensitive just make it in lower case this row of code (the string: iexplore.exe):

    IEnumerable<dynamic> FindAllIE()
            {
                var t = Type.GetTypeFromProgID("Shell.Application");
                dynamic o = Activator.CreateInstance(t);
    try
                {
                    var ws = o.Windows();
    for (int i = 0; i < ws.Count; i++)
                    {
                        var ie = ws.Item(i);
    if (ie != null && System.IO.Path.GetFileName((string)ie.FullName) == "iexplore.exe") //write iexplore.exe in lower case

    yieldreturn ie;
                    }
                }
    finally
                {
                    Marshal.FinalReleaseComObject(o);
                }
    }

                                                                                         

    this works to me...

    to get the frame element that's more an Html & JavaScript question... reference to those links:

    http://roneiv.wordpress.com/2008/01/18/get-the-content-of-an-iframe-in-javascript-crossbrowser-solution-for-both-ie-and-firefox/

    http://stackoverflow.com/questions/2026743/accessing-frames-rendered-in-webbrowser-control-in-c-net

    Hope it helps , if not reply :)


    If some code doesn't work, don't worry help is on the way.. don't forget to mark your thread as solved when done...

    Sunday, March 04, 2012 9:46 PM
  • Filenames are not case sensitive in Windows.  To properly compare filenames use String.Compare(file1, file2, StringComparison.OrdinalIgnoreCase) == 0  Technically you could use case insensitive but ordinal is preferable.

    Michael Taylor - 3/4/2012
    http://msmvps.com/blogs/p3net

    Sunday, March 04, 2012 9:49 PM
    Moderator
  • Hi.

    Thanks for reply Muli, But I have tried every thing you might imagine including upper and lower case with no success.

    Any way thanks for the suggestion.

    As for the links I will look them up now.

    Thanks again.

    Sunday, March 04, 2012 9:59 PM
  • Hi, CoolDadTx,

    I just wanted to say it is so Coooool and a great honor to see your name in my thread 3 times .

    This is enough for me to walk tall in the crouds.

    Thanks for your help so far.

    Sunday, March 04, 2012 10:02 PM
  • This code works and shows you how to get to the frames collection...

    public void FindAllIE(){
        var t = Type.GetTypeFromProgID("Shell.Application");  
        dynamic o = Activator.CreateInstance(t);
        try {   
            var ws = o.Windows();
            for (int i = 0; i < ws.Count; i++){  
                var ie = ws.Item(i);
                if (ie != null && System.IO.Path.GetFileName((string)ie.FullName) == "iexplore.exe");
                var doc2 = (mshtml.IHTMLDocument2)ie.document;
                mshtml.IHTMLFramesCollection2 frames2 = doc2.frames;
                for (int j = 0; j < frames2.length;j++ )
                {
                    var thing = frames2.item(i);                      
    
                }
                }
            }catch(Exception iox){
                        
            }           
            finally{                
                Marshal.FinalReleaseComObject(o);            
            }
    }


    JP Cowboy Coders Unite!

    Tuesday, March 06, 2012 2:23 PM
  • Note you will have to add a reference to MSHTML via the COM classes to your project.   I like your solution becuase it totally bypasses having to work with hwnd pointers.   The only thing I don't care for in this style of programming above is that everything that comes back is a COM_OBJECT... Therefore you have to infer what the type is just to grab a method or property or two...  I did this first by attempting to do a GetType().UnderlyingSystemType.Name  which told me it was a COM_OBJECT.  I then was able to luckily guess that the object type of IE had a Document property which based on past experience was a MSHTML.IHTMLDOCUMENT type which could be case into MSHTML.ITHTMLDOCUMENT2 object.

    From there it is Welcome to MSHTML world!

    Good Luck!

    JP Cowboy Coders Unite!



    Tuesday, March 06, 2012 2:25 PM
  • Hi Mr. GREAT JavaMan II

    Huge Thanks for the reply and sorry for being late to respond..

    I am now going to try the way you coded and I have a feeling it is gonna be a huge WOW it works.

    I am not really so familiar with this type of programming (COM and MSHTML ) but I will do some readings over these topics and then try to use the code you provided.

    I will get back to this post and mark as an answer as soon as I become able to copy the contents of the frame (even though I can't see how right now   :)    )

    Thanks very much again and I will be back soon.

    Wednesday, March 07, 2012 3:33 PM
  • Np dude glad to help, vote me some points ok?

    JP Cowboy Coders Unite!

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:25 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:19 PM
    Wednesday, March 07, 2012 4:39 PM
  • OK,, of course OK...

    Hope I can work it out ... please wish me luck !! and some smartness toooooo !!!! :)

    Wednesday, March 07, 2012 8:14 PM
  • I have used the following line of code to get the text inside a web page :


    IE_Window_Text = (string)ie.Document.body.innerText + Environment.NewLine;

    Now as the web page layout changed , and it is now using Frames inside the webpage, the line above is not able to catch the text which we need as it is now placed in a Frame, and it instead catches the text of the webpage without the contents of the Frames,,,

    How can I get the contents inside the frame to get my App up and running again??

    Your "IE_Window_Text" variable leads me to believe you are just wanting to get the window title for each IE window? Am I correct?

    Aaron Chapman

    Wednesday, March 07, 2012 9:33 PM
  • Hi Mr Aaron Chapman,

    Thanks for the reply.

    Indeed the name "IE_Window_Text" is just a "maybe not the best" name for a variable, but it does the job, right :)

    What I want really is getting the text ((ALL THE TEXTs )) that are shown on the webpage opened in the current IE window... even the text in the FRAMEs shown on that page.

    I have been trying to get this done for a while with no luck , until Mr.Javaman showed up with some usefull suggestions that might help,, even though I am not able to use them successfully until the moment.

    Anyways, thanks for the reply again and any help is welcome.... :)

    Wednesday, March 07, 2012 10:37 PM
  • Windows 7 intel 64-Bit is the currently running OS with VS2010 on it....

    XP SP3 with VS2008 was the platform used to develop the old school app before we upgraded to W7

    Now, to be precise, in the web page shown there are 3 FRAMES where on of them (the one in the center of the page) shows some textual data,,,,and those TEXTs are the goal... I need to copy them,,, apply the REGEX I have previously used on them,,, EXTRACT some details and print them finally...

    Hope this makes things clear enough, and sorry for any confusion caused

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:23 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:17 PM
    Wednesday, March 07, 2012 10:46 PM
  • So what you have to do is go through each of the frames and pull out each frame's MSHTML.Document2.  Contained within that is a HTMLELEMENT collection or as Aaron mentioned the entire body which is the same thing as the HTML tag Body...  You can get all of the HTML markup via the Body element.  However, if you know an element name or ID you can get the value of the HTMLELEMENT directly  like this:

    var o = document.getElementById("msdn");
    var sContentAttr = o.getAttribute("href");
    

    Which would get the element named MSDN which is a link or some other element that has an HREF attribute.  (Like and IFRAME or even a FRAME).  sContentAttr would then hold the string of the HREF like http://www.msdn.com

    JP Cowboy Coders Unite!

    Wednesday, March 07, 2012 10:46 PM
  • WOOOOW Mr.Javaman II

    A real expert you are...

    I am going to try it right away, I will be right back As Soon As I Do it Right..

    Thanks for all the help man

    Appreciat it...   :)

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:26 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:19 PM
    Wednesday, March 07, 2012 10:51 PM
  • Pretty tuff stuff for a new guy diving into MSHTML and IE web browser internals but you're doing a good job.


    JP Cowboy Coders Unite!

    • Proposed as answer by Martin Rasch Friday, March 09, 2012 10:23 PM
    • Unproposed as answer by MarcDModerator Saturday, March 10, 2012 6:17 PM
    Thursday, March 08, 2012 12:04 AM
  • Windows 7 intel 64-Bit is the currently running OS with VS2010 on it....

    XP SP3 with VS2008 was the platform used to develop the old school app before we upgraded to W7

    Now, to be precise, in the web page shown there are 3 FRAMES where on of them (the one in the center of the page) shows some textual data,,,,and those TEXTs are the goal... I need to copy them,,, apply the REGEX I have previously used on them,,, EXTRACT some details and print them finally...

    Hope this makes things clear enough, and sorry for any confusion caused


    Yes it works for me :)

    Martin Rasch

    Friday, March 09, 2012 10:29 PM
  • Hi,

    Any update of this problem?   Not_An_Expert, if the replies can solve your questions here, please help to mark them as the answers to benefit more community members.

    Good day, all!

    Thanks


    Michael Sun [MSFT]
    MSDN Community Support | Feedback to us

    • Proposed as answer by Martin Rasch Monday, March 12, 2012 2:49 AM
    • Unproposed as answer by MarcDModerator Monday, March 12, 2012 4:43 PM
    Monday, March 12, 2012 1:41 AM
    Moderator
  • Hi,

    So Late Yeah,, So Sorrrrry

    Mr. Great Javaman II has been so helpful and the solutions he came up with are a HUGE success... WOOOW.

    So many thanks Mr. Javaman II..

    By the way::

    I voted you some point dude... :)

    Saturday, April 14, 2012 5:07 PM