none
グローバル変数 RRS feed

  • 質問

  • お世話になります。

    ネットにあったMicrosoft EdgeのURLとTitleを得るコードです(作者の方に感謝いたします)。

    起動中のMicrosoft EdgeからタイトルとURLを取得するC#コード(DOM編) | 初心者備忘録
    http://www.ka-net.org/blog/?p=6283

    using System; 
    using System.Text;
    using System.Runtime.InteropServices; 
    
    namespace Sample 
    { 
      class Program 
      { 
        [Flags] 
        private enum SendMessageTimeoutFlags : uint 
        { 
          SMTO_NORMAL = 0x0000, 
          SMTO_BLOCK = 0x0001, 
          SMTO_ABORTIFHUNG = 0x0002, 
          SMTO_NOTIMEOUTIFNOTHUNG = 0x0008, 
          SMTO_ERRORONEXIT = 0x0020 
        } 
    
        private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
        private static extern bool EnumWindows(Win32Callback lpEnumFunc, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
    
        private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam); 
    
        [DllImport("user32.dll", SetLastError = true)] 
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 
        [DllImport("user32.dll", CharSet = CharSet.Auto)] 
        private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 
        [DllImport("oleacc.dll", PreserveSig=false)] 
        [return: MarshalAs(UnmanagedType.Interface)] 
        private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern uint RegisterWindowMessage(string lpString); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result); 
    
        public static void Main(string[] args) 
        { 
          IntPtr hEdge = IntPtr.Zero; 
          Win32Callback proc = new Win32Callback(EnumWindowsProc); 
    
          EnumWindows(proc, ref hEdge); 
          if (hEdge != IntPtr.Zero) { 
            Win32Callback childProc = new Win32Callback(EnumChildProc); 
            EnumChildWindows(hEdge, childProc, IntPtr.Zero); 
          } 
          Console.Write("Press any key to continue . . . "); 
          Console.ReadKey(true); 
        } 
     
        //get a Edge window('Windows.UI.Core.CoreWindow' Class) 
     
        private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam) 
        { 
          IntPtr hChild = IntPtr.Zero; 
          StringBuilder buf = new StringBuilder(1024); 
          StringBuilder buf2 = new StringBuilder(1024); 
          GetClassName(hWnd, buf, buf.Capacity); 
          switch (buf.ToString()) { 
            case "ApplicationFrameWindow": //normal window 
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge"); 
              if (hChild != IntPtr.Zero) { 
                lParam = hChild; 
                return false; 
              } 
              break; 
    
            case "Windows.UI.Core.CoreWindow": //minimized window  
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", ""); 
              GetWindowText(hWnd, buf2, buf2.Capacity); 
              if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge") { 
                lParam = hWnd; 
                return false; 
              } 
              break; 
          } 
          return true; 
        } 
        //get 'Internet Explorer_Server' window 
        private static bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam) 
        { 
          dynamic doc = null; 
          StringBuilder buf = new StringBuilder(1024); 
          GetClassName(hWnd, buf, buf.Capacity); 
          if (buf.ToString() == "Internet Explorer_Server") { 
            doc = GetHTMLDocumentFromWindow(hWnd); 
            if (doc != null) { 
              Console.WriteLine(doc.Title + ", " + doc.url); //get document title & url 
            } 
          } 
          return true; 
        } 
        //get HTMLDocument object 
        private static object GetHTMLDocumentFromWindow(IntPtr hWnd) 
        { 
          UIntPtr lRes; 
          object doc = null; 
          Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637"); 
          uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT"); 
          if (nMsg != 0) { 
            SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes); 
            if (lRes != UIntPtr.Zero) { 
              doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero); 
            } 
          } 
          return doc; 
        } 
      } 
    } 


    原文では新しいものから古いものにさかのぼって表示されてしまいます。これを順番通りにするためにList<T>を使いReverseしその後テキストファイルに出力したく、改変しましたが、グローバル変数から逃れられず困っています。

    改変したのが以下です、

    using System; 
    using System.IO;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Collections.Generic;
    
    namespace Sample 
    { 
      class Program 
      { 
        [Flags] 
        private enum SendMessageTimeoutFlags : uint 
        { 
          SMTO_NORMAL = 0x0000, 
          SMTO_BLOCK = 0x0001, 
          SMTO_ABORTIFHUNG = 0x0002, 
          SMTO_NOTIMEOUTIFNOTHUNG = 0x0008, 
          SMTO_ERRORONEXIT = 0x0020 
        } 
    
    	const string PATH = "edge_hisstory.txt";
    	static List<string> lst = new List<string>();
    	
        private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
        private static extern bool EnumWindows(Win32Callback lpEnumFunc, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
        private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam); 
        [DllImport("user32.dll", SetLastError = true)] 
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 
        [DllImport("user32.dll", CharSet = CharSet.Auto)] 
        private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 
        [DllImport("oleacc.dll", PreserveSig=false)] 
        [return: MarshalAs(UnmanagedType.Interface)] 
        private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern uint RegisterWindowMessage(string lpString); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result); 
    
        public static void Main(string[] args) 
        { 
            //string path = "edge_hisstory.txt";
            // This text is added only once to the file.
            if (File.Exists(@PATH))  File.Delete(@PATH);
    
    	using (StreamWriter sw = File.CreateText(@PATH)) 
            {
              sw.WriteLine(DateTime.Today.ToString());
            }	
    
    		
          IntPtr hEdge = IntPtr.Zero; 
          Win32Callback proc = new Win32Callback(EnumWindowsProc); 
    	  
          EnumWindows(proc, ref hEdge); 
          if (hEdge != IntPtr.Zero) { 
            Win32Callback childProc = new Win32Callback(EnumChildProc); 
            EnumChildWindows(hEdge, childProc, IntPtr.Zero); 
          } 
    	  
            lst.Reverse();
    	using (StreamWriter sw = File.AppendText(PATH)) 
    	{
    	  foreach(string con in lst)
              {
    	      Console.WriteLine(con);
                  sw.WriteLine(con);
              }
    	}
    
    	  
    	   // urltitleを記したTextファイルを起動する
    	    System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
    		hProcess.StartInfo.FileName = @PATH;
    		bool result = hProcess.Start();
    		hProcess.Close();	  
    		
          //Console.Write("Press any key to continue . . . "); 
          Console.ReadKey(); 
        } 
     
        //get a Edge window('Windows.UI.Core.CoreWindow' Class) 
     
        private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam) 
        { 
          IntPtr hChild = IntPtr.Zero; 
          StringBuilder buf = new StringBuilder(1024); 
          StringBuilder buf2 = new StringBuilder(1024); 
          GetClassName(hWnd, buf, buf.Capacity); 
          switch (buf.ToString()) { 
            case "ApplicationFrameWindow": //normal window 
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge"); 
              if (hChild != IntPtr.Zero) { 
                lParam = hChild; 
                return false; 
              } 
              break; 
    
            case "Windows.UI.Core.CoreWindow": //minimized window  
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", ""); 
              GetWindowText(hWnd, buf2, buf2.Capacity); 
              if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge") { 
                lParam = hWnd; 
                return false; 
              } 
              break; 
          } 
          return true; 
        } 
        //get 'Internet Explorer_Server' window 
        private static bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam) 
        { 
    	    //using (StreamWriter sw = File.AppendText(PATH)) 
    
          dynamic doc = null; 
          StringBuilder buf = new StringBuilder(1024); 
          GetClassName(hWnd, buf, buf.Capacity); 
          if (buf.ToString() == "Internet Explorer_Server") { 
            doc = GetHTMLDocumentFromWindow(hWnd); 
            if (doc != null) { 
    //          Console.WriteLine(doc.Title); //get document title & url 
    //          Console.WriteLine(doc.url); //get document title & url 
    		  lst.Add(doc.url);
    		  lst.Add(doc.Title);
    //        sw.WriteLine(doc.Title);
    //        sw.WriteLine(doc.url);
              } 
            }
          
    	  
          return true; 
        } 
        //get HTMLDocument object 
        private static object GetHTMLDocumentFromWindow(IntPtr hWnd) 
        { 
          UIntPtr lRes; 
          object doc = null; 
          Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637"); 
          uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT"); 
          if (nMsg != 0) { 
            SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes); 
            if (lRes != UIntPtr.Zero) { 
              doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero); 
            } 
          } 
          return doc; 
        } 
      } 
    } 

    このグローバル変数から逃れようと、以下のサンプルを組みました。

    using System; using System.IO; using System.Collections.Generic; namespace stacks { public class gbllst { private static List<string> lst = new List<string>(); public static List<string> additions { get { return lst; } set { lst = value; } } } class gbls { static void Main() { List<string> lst2 = new List<string>(); // 繰り返し呼ばれる。 for (int i = 0; i < 3; i++) { setval(); } lst2 = gbllst.additions; lst2.Reverse(); foreach (string con in lst2) { Console.WriteLine("==> {0}",con); //sw.WriteLine(con); } Console.WriteLine("Fin"); Console.ReadKey();

    } // 引数も戻り値も使えない(使用中) public static bool setval() { //gbllst.lst.Add("A"); gbllst.additions.Add("a"); gbllst.additions.Add("b"); gbllst.additions.Add("c"); return true; } } }

    これも、staticである、インスタンスを作成せずにどこからでも使える以上、グローバル変数ということになるのでしょうか。あとは参照渡しを使う方法でしょうが、原文の「EnumChildProc」の引数が書けません。








    2016年5月9日 8:54

回答

  • 関数内に匿名メソッドでコールバック関数を定義してやるといいです。
    コールバックのrefは邪魔なので外します。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.IO;
    namespace ConsoleApplication1
    {
        class Program
        {
            [Flags]
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
            private delegate bool Win32Callback(IntPtr hWnd,  IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumWindows(Win32Callback lpEnumFunc, IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
    
            private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result);
    
            const string PATH = "edge_hisstory.txt";
    
            public static void Main(string[] args)
            {
                //string path = "edge_hisstory.txt";
                // This text is added only once to the file.
                if (File.Exists(PATH)) File.Delete(PATH);
    
                using (StreamWriter sw = File.CreateText(PATH))
                {
                    sw.WriteLine(DateTime.Today.ToString());
                }
    
                List<IntPtr> hEdges = new List<IntPtr>();
                Win32Callback proc = new Win32Callback((hWnd, p) =>
                {
                    IntPtr hChild = IntPtr.Zero;
                    StringBuilder buf = new StringBuilder(1024);
                    StringBuilder buf2 = new StringBuilder(1024);
                    GetClassName(hWnd, buf, buf.Capacity);
                    switch (buf.ToString())
                    {
                        case "ApplicationFrameWindow": //normal window 
                            hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge");
                            if (hChild != IntPtr.Zero)
                            {
                                hEdges.Add(hChild);
                                return false;
                            }
                            break;
    
                        case "Windows.UI.Core.CoreWindow": //minimized window  
                            hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", "");
                            GetWindowText(hWnd, buf2, buf2.Capacity);
                            if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge")
                            {
                                hEdges.Add(hWnd);
                                return false;
                            }
                            break;
                    }
                    return true;
                });
    
                EnumWindows(proc,IntPtr.Zero);
    
                List<string> lst = new List<string>();
                if (hEdges.Count>0)
                {
                    Win32Callback childProc = new Win32Callback((hWnd, p) =>
                    {
                        dynamic doc = null;
                        StringBuilder buf = new StringBuilder(1024);
                        GetClassName(hWnd, buf, buf.Capacity);
                        if (buf.ToString() == "Internet Explorer_Server")
                        {
                            doc = GetHTMLDocumentFromWindow(hWnd);
                            if (doc != null)
                            {
                                lst.Add(doc.url);
                                lst.Add(doc.Title);
                            }
                        }
                        return true;
                    });
                    foreach (IntPtr hEdge in hEdges)
                    {
                        EnumChildWindows(hEdge, childProc, IntPtr.Zero);
                    }
                }
    
                lst.Reverse();
                using (StreamWriter sw = File.AppendText(PATH))
                {
                    foreach (string con in lst)
                    {
                        Console.WriteLine(con);
                        sw.WriteLine(con);
                    }
                }
    
                // urltitleを記したTextファイルを起動する
                System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
                hProcess.StartInfo.FileName = @PATH;
                bool result = hProcess.Start();
                hProcess.Close();
    
                //Console.Write("Press any key to continue . . . "); 
                Console.ReadKey(); ;
            }
    
            private static object GetHTMLDocumentFromWindow(IntPtr hWnd)
            {
                UIntPtr lRes;
                object doc = null;
                Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
                uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                if (nMsg != 0)
                {
                    SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != UIntPtr.Zero)
                    {
                        doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero);
                    }
                }
                return doc;
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク HISSTORY_T 2016年5月13日 11:00
    2016年5月9日 10:04
  • 2. GCHandleを使ってIntPtrでやりとり。ただしこの場合、EnumChildWindowsに渡すデリゲート型の第2引数はref IntPtrではなくIntPtrにする必要があります。

    private delegate bool EnumChildCallback(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, IntPtr lParam);

    var list = new List<string>(); var hlist = GCHandle.Alloc(list); try {     EnumChildWindows(hEdge, childProc, GCHandle.ToIntPtr(hlist)); } finally {     hlist.Free(); } private static bool EnumChildProc(IntPtr hWnd, IntPtr lParam){    var list = (List<string>)GCHandle.FromIntPtr(lParam);    ... }

    3. クラスにする
    class CallbackWrapper {
        public CallbackWrapper() {
            this.Values = new List<string>();
        }
        public List<string> Values { get; private set; }
        public bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam) {
            this.Values.Add(...);
        }
    }
    
    var callback = new CallbackWrapper();
    var childProc = new Win32Callback(callback.EnumChildProc);
    EnumChildWindows(hEdge, childProc, IntPtr.Zero);
    // foreach (var txt in callback.Values) Debug.Print(txt);



    • 編集済み Hongliang 2016年5月9日 10:49
    • 回答としてマーク HISSTORY_T 2016年5月13日 11:00
    2016年5月9日 10:43

すべての返信

  • 関数内に匿名メソッドでコールバック関数を定義してやるといいです。
    コールバックのrefは邪魔なので外します。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.IO;
    namespace ConsoleApplication1
    {
        class Program
        {
            [Flags]
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
            private delegate bool Win32Callback(IntPtr hWnd,  IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumWindows(Win32Callback lpEnumFunc, IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
    
            private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam);
    
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result);
    
            const string PATH = "edge_hisstory.txt";
    
            public static void Main(string[] args)
            {
                //string path = "edge_hisstory.txt";
                // This text is added only once to the file.
                if (File.Exists(PATH)) File.Delete(PATH);
    
                using (StreamWriter sw = File.CreateText(PATH))
                {
                    sw.WriteLine(DateTime.Today.ToString());
                }
    
                List<IntPtr> hEdges = new List<IntPtr>();
                Win32Callback proc = new Win32Callback((hWnd, p) =>
                {
                    IntPtr hChild = IntPtr.Zero;
                    StringBuilder buf = new StringBuilder(1024);
                    StringBuilder buf2 = new StringBuilder(1024);
                    GetClassName(hWnd, buf, buf.Capacity);
                    switch (buf.ToString())
                    {
                        case "ApplicationFrameWindow": //normal window 
                            hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge");
                            if (hChild != IntPtr.Zero)
                            {
                                hEdges.Add(hChild);
                                return false;
                            }
                            break;
    
                        case "Windows.UI.Core.CoreWindow": //minimized window  
                            hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", "");
                            GetWindowText(hWnd, buf2, buf2.Capacity);
                            if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge")
                            {
                                hEdges.Add(hWnd);
                                return false;
                            }
                            break;
                    }
                    return true;
                });
    
                EnumWindows(proc,IntPtr.Zero);
    
                List<string> lst = new List<string>();
                if (hEdges.Count>0)
                {
                    Win32Callback childProc = new Win32Callback((hWnd, p) =>
                    {
                        dynamic doc = null;
                        StringBuilder buf = new StringBuilder(1024);
                        GetClassName(hWnd, buf, buf.Capacity);
                        if (buf.ToString() == "Internet Explorer_Server")
                        {
                            doc = GetHTMLDocumentFromWindow(hWnd);
                            if (doc != null)
                            {
                                lst.Add(doc.url);
                                lst.Add(doc.Title);
                            }
                        }
                        return true;
                    });
                    foreach (IntPtr hEdge in hEdges)
                    {
                        EnumChildWindows(hEdge, childProc, IntPtr.Zero);
                    }
                }
    
                lst.Reverse();
                using (StreamWriter sw = File.AppendText(PATH))
                {
                    foreach (string con in lst)
                    {
                        Console.WriteLine(con);
                        sw.WriteLine(con);
                    }
                }
    
                // urltitleを記したTextファイルを起動する
                System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
                hProcess.StartInfo.FileName = @PATH;
                bool result = hProcess.Start();
                hProcess.Close();
    
                //Console.Write("Press any key to continue . . . "); 
                Console.ReadKey(); ;
            }
    
            private static object GetHTMLDocumentFromWindow(IntPtr hWnd)
            {
                UIntPtr lRes;
                object doc = null;
                Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
                uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                if (nMsg != 0)
                {
                    SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != UIntPtr.Zero)
                    {
                        doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero);
                    }
                }
                return doc;
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 回答としてマーク HISSTORY_T 2016年5月13日 11:00
    2016年5月9日 10:04
  • 2. GCHandleを使ってIntPtrでやりとり。ただしこの場合、EnumChildWindowsに渡すデリゲート型の第2引数はref IntPtrではなくIntPtrにする必要があります。

    private delegate bool EnumChildCallback(IntPtr hWnd, IntPtr lParam);

    [DllImport("user32.dll")][return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, IntPtr lParam);

    var list = new List<string>(); var hlist = GCHandle.Alloc(list); try {     EnumChildWindows(hEdge, childProc, GCHandle.ToIntPtr(hlist)); } finally {     hlist.Free(); } private static bool EnumChildProc(IntPtr hWnd, IntPtr lParam){    var list = (List<string>)GCHandle.FromIntPtr(lParam);    ... }

    3. クラスにする
    class CallbackWrapper {
        public CallbackWrapper() {
            this.Values = new List<string>();
        }
        public List<string> Values { get; private set; }
        public bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam) {
            this.Values.Add(...);
        }
    }
    
    var callback = new CallbackWrapper();
    var childProc = new Win32Callback(callback.EnumChildProc);
    EnumChildWindows(hEdge, childProc, IntPtr.Zero);
    // foreach (var txt in callback.Values) Debug.Print(txt);



    • 編集済み Hongliang 2016年5月9日 10:49
    • 回答としてマーク HISSTORY_T 2016年5月13日 11:00
    2016年5月9日 10:43
  • コードの返信とライセンスの補足の記載とてもとても感謝いたします。

    (時間をとってしまって申し訳ありません。Win32APIのところで、壁が。これもC#なのですね。)

    あぁ、そうですか、メインルーチンに取り込んだんですね。

    (余談ですがブラウザで左右で見比べて読んでいましたが目がちかちかして頭に入らないので、VisualStudio (Community 2015)を持ちだしましたら、とても読みやすいんですね!普段は、身軽なNotepad++を使っていますが、これはVSですべきですね。機能がそうとう充実していて、使いきれないくらいらしいですね。)

    それにしてもこのコードはすごいですね!舞い上がってしまい時間が過ぎてしまいました。

    もうちょっと時間をください……

    もうすこしWin32APIのところの他のパターンのコードをいただけないでしょうか?自分では、

    画面上のすべてのウィンドウとそのタイトルを列挙する: .NET Tips: C#, VB.NET
    http://dobon.net/vb/dotnet/process/enumwindows.html
    ウィンドウのタイトルからプロセスを探す: .NET Tips: C#, VB.NET
    http://dobon.net/vb/dotnet/process/getprocessesbywindowtitle.html

    などを見つけたのですが、まだ読み切れません。この今回のソースとあと少しほしいです。それで読み解けそうです。無理を言ってごめんなさい。いまより簡単なもので。(確かここのAPI群はWindowsの肝のところですよね。)

    もうちょっと時間をください……

    お手数おかけします。お願いいたします。







    2016年5月9日 11:40
  • 返信遅れて申し訳ありません。3のclassにするの方は動きました。以下です、

    using System; 
    using System.IO;
    using System.Text;
    using System.Runtime.InteropServices; 
    using System.Collections.Generic;
    
    namespace Sample 
    { 
      class Program 
      { 
        [Flags] 
        private enum SendMessageTimeoutFlags : uint 
        { 
          SMTO_NORMAL = 0x0000, 
          SMTO_BLOCK = 0x0001, 
          SMTO_ABORTIFHUNG = 0x0002, 
          SMTO_NOTIMEOUTIFNOTHUNG = 0x0008, 
          SMTO_ERRORONEXIT = 0x0020 
        } 
    
    	const string PATH = "edge_hisstory.txt";
        class CallbackWrapper 
    	{
            public CallbackWrapper() 
    		{ 
                this.Values = new List<string>(); 
            } 
            public List<string> Values { get; private set; } 
            public bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam) 
    		{ 
    		   dynamic doc = null; 
               StringBuilder buf = new StringBuilder(1024); 
               GetClassName(hWnd, buf, buf.Capacity); 
               if (buf.ToString() == "Internet Explorer_Server") 
    		   { 
                 doc = GetHTMLDocumentFromWindow(hWnd); 
                 if (doc != null) 
    		     { 
                    this.Values.Add(doc.url); 
                    this.Values.Add(doc.Title); 
                 }
    	       }
    		   return true; 
    	  }		 
        } 
    	
        private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
        private static extern bool EnumWindows(Win32Callback lpEnumFunc, ref IntPtr lParam); 
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)] 
        private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam); 
        [DllImport("user32.dll", SetLastError = true)] 
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 
        [DllImport("user32.dll", CharSet = CharSet.Auto)] 
        private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); 
        [DllImport("oleacc.dll", PreserveSig=false)] 
        [return: MarshalAs(UnmanagedType.Interface)] 
        private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern uint RegisterWindowMessage(string lpString); 
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result); 
    
        public static void Main(string[] args) 
        { 
            //string path = "edge_hisstory.txt";
            // This text is added only once to the file.
            if (File.Exists(@PATH))  File.Delete(@PATH);
    
    		using (StreamWriter sw = File.CreateText(@PATH)) 
            {
              sw.WriteLine(DateTime.Today.ToString());
            }	
    
    		
          IntPtr hEdge = IntPtr.Zero; 
          Win32Callback proc = new Win32Callback(EnumWindowsProc); 
    	  
          EnumWindows(proc, ref hEdge); 
            var callback = new CallbackWrapper();
          if (hEdge != IntPtr.Zero) { 
            var childProc = new Win32Callback(callback.EnumChildProc);
            EnumChildWindows(hEdge, childProc, IntPtr.Zero);
    		// foreach (var txt in callback.Values) Debug.Print(txt);
          } 
    	  
            callback.Values.Reverse();
    		using (StreamWriter sw = File.AppendText(PATH)) 
    		{
    			foreach(string con in callback.Values)
              {
    			  Console.WriteLine(con);
                  sw.WriteLine(con);
              }
    		}
    
    	  
    	   // urltitleを記したTextファイルを起動する
    	    System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
    		hProcess.StartInfo.FileName = @PATH;
    		bool result = hProcess.Start();
    		hProcess.Close();	  
    		
          //Console.Write("Press any key to continue . . . "); 
          //Console.ReadKey(true); 
        } 
     
        //get a Edge window('Windows.UI.Core.CoreWindow' Class) 
     
        private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam) 
        { 
          IntPtr hChild = IntPtr.Zero; 
          StringBuilder buf = new StringBuilder(1024); 
          StringBuilder buf2 = new StringBuilder(1024); 
          GetClassName(hWnd, buf, buf.Capacity); 
          switch (buf.ToString()) { 
            case "ApplicationFrameWindow": //normal window 
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge"); 
              if (hChild != IntPtr.Zero) { 
                lParam = hChild; 
                return false; 
              } 
              break; 
    
            case "Windows.UI.Core.CoreWindow": //minimized window  
              hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", ""); 
              GetWindowText(hWnd, buf2, buf2.Capacity); 
              if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge") { 
                lParam = hWnd; 
                return false; 
              } 
              break; 
          } 
          return true; 
        } 
    
        //get HTMLDocument object 
        private static object GetHTMLDocumentFromWindow(IntPtr hWnd) 
        { 
          UIntPtr lRes; 
          object doc = null; 
          Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637"); 
          uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT"); 
          if (nMsg != 0) { 
            SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes); 
            if (lRes != UIntPtr.Zero) { 
              doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero); 
            } 
          } 
          return doc; 
        } 
      } 
    } 

    こうなりました。

    2の方なのですが、動きません。こんな風になっています。

    using System;
    using System.IO;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    
    namespace edge_urltitle_hongliangsan_01
    {
        class Program
        {
            [Flags]
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
            const string PATH = "edge_hisstory.txt";
    
            private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumWindows(Win32Callback lpEnumFunc, ref IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumChildWindows(IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result);
    
            private delegate bool EnumChildCallback(IntPtr hWnd, IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildCallback lpEnumFunc, IntPtr lParam);
    
            public static void Main(string[] args)
            {
                //string path = "edge_hisstory.txt";
                // This text is added only once to the file.
                if (File.Exists(@PATH)) File.Delete(@PATH);
    
                using (StreamWriter sw = File.CreateText(@PATH))
                {
                    sw.WriteLine(DateTime.Today.ToString());
                }
    
    
                IntPtr hEdge = IntPtr.Zero;
                Win32Callback proc = new Win32Callback(EnumWindowsProc);
    
                EnumWindows(proc, ref hEdge);
                var lst = new List<string>();
                if (hEdge != IntPtr.Zero)
                {
                    Win32Callback childProc = new Win32Callback(EnumChildProc);
                    var hlist = GCHandle.Alloc(lst);
                    try
                    {
                        EnumChildWindows(hEdge, childProc, GCHandle.ToIntPtr(hlist));
                    }
                    finally
                    {
                        hlist.Free();
                    }
                }
    
                lst.Reverse();
                using (StreamWriter sw = File.AppendText(PATH))
                {
                    foreach (string con in lst)
                    {
                        Console.WriteLine(con);
                        sw.WriteLine(con);
                    }
                }
    
    
                // urltitleを記したTextファイルを起動する
                System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
                hProcess.StartInfo.FileName = @PATH;
                bool result = hProcess.Start();
                hProcess.Close();
    
                //Console.Write("Press any key to continue . . . "); 
                //Console.ReadKey(true); 
            }
    
            //get a Edge window('Windows.UI.Core.CoreWindow' Class) 
    
            private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam)
            {
                IntPtr hChild = IntPtr.Zero;
                StringBuilder buf = new StringBuilder(1024);
                StringBuilder buf2 = new StringBuilder(1024);
                GetClassName(hWnd, buf, buf.Capacity);
                switch (buf.ToString())
                {
                    case "ApplicationFrameWindow": //normal window 
                        hChild = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", "Microsoft Edge");
                        if (hChild != IntPtr.Zero)
                        {
                            lParam = hChild;
                            return false;
                        }
                        break;
    
                    case "Windows.UI.Core.CoreWindow": //minimized window  
                        hChild = FindWindowEx(hWnd, IntPtr.Zero, "Spartan XAML-To-Trident Input Routing Window", "");
                        GetWindowText(hWnd, buf2, buf2.Capacity);
                        if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge")
                        {
                            lParam = hWnd;
                            return false;
                        }
                        break;
                }
                return true;
            }
            //get 'Internet Explorer_Server' window 
            private static bool EnumChildProc(IntPtr hWnd, ref IntPtr lParam)
            {
                //using (StreamWriter sw = File.AppendText(PATH)) 
                GCHandle gch = GCHandle.FromIntPtr(lParam);
                var lst = (List<string>)gch.Target;
    
                dynamic doc = null;
                StringBuilder buf = new StringBuilder(1024);
                GetClassName(hWnd, buf, buf.Capacity);
                if (buf.ToString() == "Internet Explorer_Server")
                {
                    doc = GetHTMLDocumentFromWindow(hWnd);
                    if (doc != null)
                    {
                        //          Console.WriteLine(doc.Title); //get document title & url 
                        //          Console.WriteLine(doc.url); //get document title & url 
                        lst.Add(doc.url);
                        lst.Add(doc.Title);
                        //        sw.WriteLine(doc.Title);
                        //        sw.WriteLine(doc.url);
                    }
                }
    
    
                return true;
            }
            //get HTMLDocument object 
            private static object GetHTMLDocumentFromWindow(IntPtr hWnd)
            {
                UIntPtr lRes;
                object doc = null;
                Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
                uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                if (nMsg != 0)
                {
                    SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != UIntPtr.Zero)
                    {
                        doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero);
                    }
                }
                return doc;
            }
        }
    }

    atalExecutionEngineError

    マネージ デバッグ アシスタント 'FatalExecutionEngineError' が 'D:\cs_vb\edge_urltitle\edge_urltitle_hongliang_01\edge_urltitle_hongliangsan_01\bin\Debug\edge_urltitle_hongliangsan_01.vshost.exe' で問題を検出しました。

    追加情報:ランタイムの重大なエラーが発生しました。エラーのアドレスは 0x6d8a9220、スレッド 0x4d5c です。エラー コードは 0xc0000005 です。これは CLR のバグであるか、またはユーザー コードのアンセーフまたは確認不可能な部分にバグがある可能性があります。このバグの一般的な原因には、スタックが壊れる可能性のある COM-interop または PInvoke のユーザー マーシャリング エラーが含まれています。

    =======

    です。

    よろしくお願いします。



    2016年5月9日 14:20
  • Hongliangさん、ありがとうございます。

    頑張ってみましたが2の方の

    ---

    2. GCHandleを使ってIntPtrでやりとり。ただしこの場合、EnumChildWindowsに渡すデリゲート型の第2引数はref IntPtrではなくIntPtrにする必要があります。

    ---

    が、どうにもこうにも、再現できません。これ以上待っていただくわけにもいきませんので、そうですね、どうしたらよいでしょう……

    2016年5月10日 7:35
  • 2の方、動きました。

    でも、もうちょっと待ってください。

    2016年5月11日 5:49
  • お待たせしてすみません。ご助言いただければと、いろいろ試してみたのですが、なんだかよくわからないことに…。しかしながらとても身になりました。

    ここからC/C++に入れそうな感じですね。コールバックについて別にスレッドを立てご指南いただこうと思っております。

    2の方を貼り付けておきます。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Runtime.InteropServices; 
    
    namespace edge_urltitle_hongliangsan_02._1
    {
        class Program
        {
            [Flags]
            private enum SendMessageTimeoutFlags : uint
            {
                SMTO_NORMAL = 0x0000,
                SMTO_BLOCK = 0x0001,
                SMTO_ABORTIFHUNG = 0x0002,
                SMTO_NOTIMEOUTIFNOTHUNG = 0x0008,
                SMTO_ERRORONEXIT = 0x0020
            }
    
    
            private delegate bool Win32Callback(IntPtr hWnd, ref IntPtr lParam);
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumWindows(
    		    Win32Callback lpEnumFunc, ref IntPtr lParam);
    
            private delegate bool EnumChildCallback(IntPtr hWnd, IntPtr lParam);     // <---
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumChildWindows(
    		    IntPtr hWndParent, EnumChildCallback lpEnumFunc, IntPtr lParam);     // --->
    
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool EnumChildWindows(
    		    IntPtr hWndParent, Win32Callback lpEnumFunc, IntPtr lParam);
            [DllImport("user32.dll", SetLastError = true)]
            private static extern IntPtr FindWindowEx(
    		    IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern int GetClassName(
    		    IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
            [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern int GetWindowText(
    		    IntPtr hWnd, StringBuilder lpString, int nMaxCount);
            [DllImport("oleacc.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.Interface)]
            private static extern object ObjectFromLresult(
    		    UIntPtr lResult, [MarshalAs(UnmanagedType.LPStruct)] Guid refiid, IntPtr wParam);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern uint RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessageTimeout(
    		    IntPtr windowHandle, uint Msg, IntPtr wParam, IntPtr lParam, 
    			SendMessageTimeoutFlags flags, uint timeout, out UIntPtr result);
    
            const string PATH = "edge_hisstory.txt";
    
            public static void Main(string[] args)
            {
                if (File.Exists(@PATH)) File.Delete(@PATH);
    
                using (StreamWriter sw = File.CreateText(@PATH))
                {
                    sw.WriteLine(DateTime.Now.ToString());
                }
    
                IntPtr hEdge = IntPtr.Zero;
                Win32Callback proc = new Win32Callback(EnumWindowsProc);
                var list = new List<string>();    // <---
    
                EnumWindows(proc, ref hEdge);
                if (hEdge != IntPtr.Zero)
                {
                    var hlist = GCHandle.Alloc(list);     // <---
    	    		//Win32Callback childProc = new Win32Callback(EnumChildProc);
                    EnumChildCallback childCallback = new EnumChildCallback(EnumChildProc);     // <---
                    try
                    {
                        EnumChildWindows(hEdge, childCallback, GCHandle.ToIntPtr(hlist));
                    }
                    finally
                    {
                        hlist.Free();
                    }
                }     // ---> 
                list.Reverse();
                using (StreamWriter sw = File.AppendText(@PATH))
                {
                    foreach (string con in list)
                    {
                        Console.WriteLine(con);
                        sw.WriteLine(con);
                    }
                }
                // urltitleを記したTextファイルを起動する
                System.Diagnostics.Process hProcess = new System.Diagnostics.Process();
                hProcess.StartInfo.FileName = @PATH;
                bool result = hProcess.Start();
                hProcess.Close();
    
                Console.Write("Press any key to continue . . . ");
                Console.ReadKey(true);
            }
    
            //get a Edge window('Windows.UI.Core.CoreWindow' Class) 
            private static bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam)
            {
                IntPtr hChild = IntPtr.Zero;
                StringBuilder buf = new StringBuilder(1024);
                StringBuilder buf2 = new StringBuilder(1024);
                GetClassName(hWnd, buf, buf.Capacity);
                switch (buf.ToString())
                {
                    case "ApplicationFrameWindow": //normal window 
                        hChild = FindWindowEx(hWnd, IntPtr.Zero, 
    					    "Windows.UI.Core.CoreWindow", "Microsoft Edge");
                        if (hChild != IntPtr.Zero)
                        {
                            lParam = hChild;
                            return false;
                        }
                        break;
    
                    case "Windows.UI.Core.CoreWindow": //minimized window  
                        hChild = FindWindowEx(hWnd, IntPtr.Zero, 
    					    "Spartan XAML-To-Trident Input Routing Window", "");
                        GetWindowText(hWnd, buf2, buf2.Capacity);
                        if (hChild != IntPtr.Zero && buf2.ToString() == "Microsoft Edge")
                        {
                            lParam = hWnd;
                            return false;
                        }
                        break;
                }
                return true;
            }
            //get 'Internet Explorer_Server' window 
            private static bool EnumChildProc(IntPtr hWnd, IntPtr lParam)     // <--- ref
            {
                //var list = (List<string>)GCHandle.FromIntPtr(lParam);
                GCHandle gch = GCHandle.FromIntPtr(lParam);     // <--- 
                //List<string> list = (List<string>)gch.Target as List<string>;     // <---
                List<string> list = (List<string>)gch.Target;     // <---
                dynamic doc = null;
                StringBuilder buf = new StringBuilder(1024);
                GetClassName(hWnd, buf, buf.Capacity);
                if (buf.ToString() == "Internet Explorer_Server")
                {
                    doc = GetHTMLDocumentFromWindow(hWnd);
                    if (doc != null)
                    {
                        //Console.WriteLine(doc.Title + ", " + doc.url); //get document title & url 
                        list.Add(doc.url);
                        list.Add(doc.Title);
    
                    }
                }
                return true;
            }
            //get HTMLDocument object 
            private static object GetHTMLDocumentFromWindow(IntPtr hWnd)
            {
                UIntPtr lRes;
                object doc = null;
                Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
                uint nMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                if (nMsg != 0)
                {
                    SendMessageTimeout(hWnd, nMsg, IntPtr.Zero, IntPtr.Zero, 
    				    SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);
                    if (lRes != UIntPtr.Zero)
                    {
                        doc = ObjectFromLresult(lRes, IID_IHTMLDocument, IntPtr.Zero);
                    }
                }
                return doc;
            }
        }
    }

    重ね重ね感謝です。

    gekkaさん、Hongliangさん、ありがとうございました。





    2016年5月13日 10:58