質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

Q&A

解決済

3回答

12358閲覧

C# windows10上でフォームの親にデスクトップウィンドウを設定するとおかしな挙動をする

sheephuman

総合スコア112

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

2グッド

1クリップ

投稿2016/11/07 08:55

編集2017/06/18 13:46

http://www.orangemaker.sakura.ne.jp/labo/memo/sdk-mfc/win7Desktop.html

を読んで"WorkerW"でいいんだろうと思い、buttonに端から登録して実行してみました。すると、非表示にはなりませんがおかしな挙動を取ります。
ここでは、タスクバー内でアイコンがスライドするような動きですね。

目的は「フォーム最背面に移動させる」です。

最背面に移動させる方法自体は見つけたのですが、OS上の違いなどあるのではと思い質問してみました。windows10上でこのコードを動作させるには何が必要なのでしょうか?

サンプルプロジェクト
https://box.yahoo.co.jp/guest/viewer?sid=box-l-jjsgnkx53gwi3lt2r7nmvpbfvm-1001&uniqid=29f8833a-4f18-4f76-8479-374b703779d4&viewtype=detail

C#

1using System; 2using System.Runtime.InteropServices; 3using System.Windows.Forms; 4 5namespace WindowsFormsApplication9 6{ 7 public partial class Form1 : Form 8 { 9 // HWND GetDesktopWindow(VOID); 10 [DllImport("User32.Dll")] 11 static extern IntPtr GetDesktopWindow(); 12 13 14 [DllImport("User32.dll")] 15 static extern int SetForegroundWindow( 16 IntPtr hWnd 17 ); 18 [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] 19 static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 20 21 [System.Runtime.InteropServices.DllImport("user32.dll")] 22 static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 23 24 25 public Form1() 26 { 27 InitializeComponent(); 28 29 MinimizeBox = false; 30 } 31 32 private void Form1_Deactivate(object sender, EventArgs e) 33 { 34 MinimizeBox = false; 35 // this.Focus(); 36 this.TopMost = true; 37 // this.TopMost = false; 38 39 } 40 41 private void button1_Click(object sender, EventArgs e) 42 { 43 44 //http://nanoappli.com/blog/archives/1844 45 46 IntPtr WinHandle = FindWindow(null, "WorkerW"); 47 if (WinHandle != null) 48 { 49 SetParent(this.Handle, WinHandle); 50 51 52 } 53 54 } 55 56 private void button2_Click(object sender, EventArgs e) 57 { 58 IntPtr WinHandle = GetDesktopWindow(); 59 if (WinHandle != null) 60 { 61 SetParent(this.Handle, WinHandle); 62 } 63 } 64 65 private void button4_Click(object sender, EventArgs e) 66 { 67 IntPtr WinHandle = FindWindow(null, "SHELLDLL_DefView"); 68 if (WinHandle != null) 69 { 70 SetParent(this.Handle, WinHandle); 71 72 73 } 74 } 75 76 77 78 79 } 80} 81 82```」 83 84 85挙動を記録した動画 86https://www.youtube.com/watch?v=BKodO_PNwhQ&feature=youtu.be
mercurian-teto, arakawariver👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hmmm

2017/06/18 13:39

もう解決していますが、この質問内容ではおかしな挙動が何なのか説明されていません。目的も「フォーム最背面に移動させる」とありますが動画を見る限りは移動しているように見えるためおかしな挙動がなんなのか分かりません。また記載されているコードの中にSetForgroundがあり、最背面にしたいのか最前面にしないのか意味が分かりません。説明不足です。
sheephuman

2017/06/18 13:44

えー確かに明示はしてませんが・・・動画冒頭にタスクバー内のアイコンがスライドするような動作になっているのが分かると思います。
sheephuman

2017/06/18 13:54

というかwindows10で実行すれば最背面に移動するかどうか分かるハズなんだが。
hmmm

2017/06/18 15:31

例えば「このプログラムの何番目のボタンを押したときに○○という動作をします。これを○○にするにはどうすればいいですか?」と聞かれれば動かそうと思いますが、何が問題なのかが分からない説明では動かそうとは思いませんよ。
sheephuman

2017/06/18 15:32

いや、解決してるんだけどもう。
guest

回答3

0

自己解決

冒頭のコードを改造しようとして、

C#

1 2 [DllImport("USER32.DLL", EntryPoint = "FindWindowEx")] 3 private static extern IntPtr FindWindowEx(IntPtr hWnd1, IntPtr hWnd2, string lpsz1, string lpsz2); 4 5 6 [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)] 7 static extern IntPtr FindWindow(string lpClassName, string lpWindowName); 8 9 [System.Runtime.InteropServices.DllImport("user32.dll")] 10 static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 11 12 13 private void button1_Click_1(object sender, EventArgs e) 14 { 15 IntPtr WinHandle = FindWindow("SHELLDLL", "Program Manager"); 16 if (WinHandle != null) 17 { 18 SetParent(this.Handle, WinHandle); 19 } 20 } 21 22 private void button2_Click(object sender, EventArgs e) 23 { 24 IntPtr hWnd; 25 hWnd = FindWindow("SHELLDELL_DefView", "Program Manager"); 26 27 hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null); 28 // hWnd = FindWindowEx(hWnd, IntPtr.Zero, "SysListView32", null); 29 30 if (hWnd != null && hWnd != IntPtr.Zero) 31 { 32 SetParent(this.Handle, hWnd); 33 } 34 35 // hDt = FindWindowEx(hDt, IntPtr.Zero, "SHELLDLL_DefView", null); 36 ////↑この"SHELLDLL_DefView"がキモ。このクラス名が入っていな //いと、Program Managerだろうと何だろうとデスクトップウィンドウを取得できない。 37 //if (hDt != null && hDt != IntPtr.Zero) 38 //{ 39 // SetParent(this.Handle, hDt); 40 //} 41 42 } 43 } 44}

などとしてみましたが、一向に動作せず諦めました。

確実なやり方はShellDLL_DefViewを持っているProgram Managerを、Win32APIを利用して列挙させるという方法になるようです。こんなややこしい方法をとらずに直接setParent出来たらと思ったのですが・・・・。

解決方法

C#

1 public delegate bool EnumWindowCallBack(IntPtr hwnd, IntPtr lParam); 2 3 [DllImport("USER32.DLL", EntryPoint = "FindWindowEx")] 4 private static extern IntPtr FindWindowEx(IntPtr hWnd1, IntPtr hWnd2, string lpsz1, string lpsz2); 5 6 // SetParent 関数 7 [DllImport("USER32.DLL", CharSet = CharSet.Auto)] 8 private static extern System.IntPtr SetParent( 9 System.IntPtr hWndChild, 10 System.IntPtr hWndNewParent 11 ); 12 13 [DllImport("USER32.Dll")] 14 static extern int EnumWindows(EnumWindowCallBack x, IntPtr y); 15 16 [DllImport("User32.Dll", CharSet = CharSet.Unicode)] 17 public static extern int GetClassName(IntPtr hWnd, StringBuilder s, int nMaxCount); 18 19 20 21 // ウィンドウを列挙するためのコールバックメソッド 22 private bool EnumerateWindow(IntPtr hWnd, IntPtr lParam) 23 { 24 StringBuilder sbClassName = new StringBuilder(256); 25 int result = GetClassName(hWnd, sbClassName, 256); 26 string className = sbClassName.ToString(); 27 if (className.Equals("WorkerW") || className.Equals("Progman")) 28 { 29 IntPtr hDt = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null); 30              //↑この"SHELLDLL_DefView"がキモ。このクラス名が入っていな //いと、Program Managerだろうと何だろうとデスクトップウィンドウを取得できない。 31 if (hDt != null && hDt != IntPtr.Zero) 32 { 33 SetParent(this.Handle, hDt); 34 } 35 } 36 return true; 37 } 38 39 40 private void button1_Click_1(object sender, EventArgs e) 41 { 42 EnumWindows(EnumerateWindow, IntPtr.Zero); 43 } 44 45

まとめ記事

投稿2016/11/08 14:10

編集2017/06/18 13:53
sheephuman

総合スコア112

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sheephuman

2017/06/18 13:05

ちなみに、「おかしな挙動」の事ですが これは SetParent(this.Handle, hDt); が失敗すると自身を親としてセットされます(多分)。 この挙動を利用して、デスクトップの子ウィンドウに設定 → 元に戻す という動作を実現できました。
guest

0

「WorkerW」から「Program Manager」に変えてみてください。
参考URL
http://nanoappli.com/blog/archives/1844

投稿2016/11/07 09:28

編集2016/11/07 09:30
ishi9

総合スコア1294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sheephuman

2016/11/07 09:39

やってみましたが、全く何も表示されなくなってしまいますよ。 そもそもそっちが、こちらで提示したコードですし。ちゃんと実行しました? http://dobon.net/vb/dotnet/process/enumwindows.htmlを 実行したら”Program Manager”の方が見つかったので、後はDefViewとかいうのが入ってるのを見つければいいっぽいです。 やはりProgram Managerであってるらしいことは分かりました。 そっちの方も、http://ja.stackoverflow.com/questions/10572/c-%e9%80%8f%e9%81%8e%e3%81%97%e3%81%9f%e3%83%95%e3%82%a9%e3%83%bc%e3%83%a0%e3%82%92%e6%9c%80%e8%83%8c%e9%9d%a2%e3%81%ab%e3%81%97%e3%81%9f%e3%81%84%e3%81%ae%e3%81%a0%e3%81%8c?rq=1   の if (className.Equals("WorkerW") || className.Equals("Progman")) { IntPtr hDt = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null); if (hDt != null && hDt != IntPtr.Zero) { SetParent(this.Handle, hDt); } } のようにすればよいと分かりました。 暫くしたら自己解決扱いにしようと思います。
ishi9

2016/11/07 09:46

誤った回答を提示したようで申し訳ありませんでした。 自己解決したようで何よりです。
sheephuman

2016/11/08 14:20

そもそもその記事自体が古いというか、環境が限られてるのか分かりませんが。 単純に IntPtr WinHandle = FindWindow("SHELLDLL_DefView", "Program Manager"); としてもダメだったんで、わざわざ別の列挙APIを使わないとムリなんですかね。
guest

0

ちなみに、「おかしな挙動」の事ですが
これは SetParent(this.Handle, hDt); が失敗すると自身を親としてセットし直されされます(多分)。
このときタスクバー内のアイコンが再表示されるようです。

あたかもスライド
この挙動を利用して、デスクトップの子ウィンドウに設定 → 元に戻す という動作を実現できました。

投稿2017/06/18 13:49

sheephuman

総合スコア112

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問