DOBON.NET DOBON.NETプログラミング掲示板過去ログ

CをC#に移植したときに問題が発生しました

環境/言語:[Win7U .NET 4.0 ]
分類:[.NET]

こちらのサイトをC#に移植したのですが
http://katahiromz.web.fc2.com/win32/desktop.html

新しいデスクトップの作成はできたのですがメッセージボックス(MessageBox.Showの方)をしたところ元のデスクトップのほうに表示されてしまい、元のデスクトップに戻れなくなってしまいました

このソースの中にはスレッドを新しいデスクトップに移すメソッドがあったと思うのですが、どうしてうまくいかなかったのでしょうか。
API郡はdllにしているのでプログラムの中にはDllImportはしていません
[dll : user32クラス]
http://msdn.microsoft.com/ja-jp/library/cc364750.aspx
[DllImport("user32.dll")]
public static extern IntPtr GetThreadDesktop(uint dwThreadId);
http://msdn.microsoft.com/ja-jp/library/cc410938.aspx
[DllImport("user32.dll")]
public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, DESKTOP dwDesiredAccess);
http://msdn.microsoft.com/ja-jp/library/cc410718.aspx
[DllImport("user32.dll", EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = true)]
public static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, DESKTOP dwDesiredAccess, ref SECURITY_ATTRIBUTES lpsa);
http://msdn.microsoft.com/ja-jp/library/cc411078.aspx
[DllImport("user32.dll")]
public static extern Boolean SetThreadDesktop(IntPtr hDesktop);
http://msdn.microsoft.com/ja-jp/library/cc411215.aspx
[DllImport("user32.dll")]
public static extern Boolean SwitchDesktop(IntPtr hDesktop);
http://msdn.microsoft.com/ja-jp/library/cc410665.aspx
[DllImport("user32.dll")]
public static extern Boolean CloseDesktop(IntPtr hDesktop);
[プログラム側]
const DESKTOP access=(DESKTOP.DESKTOP_CREATEMENU | DESKTOP.DESKTOP_CREATEWINDOW |
DESKTOP.DESKTOP_READOBJECTS | DESKTOP.DESKTOP_SWITCHDESKTOP | DESKTOP.DESKTOP_WRITEOBJECTS |
DESKTOP.DESKTOP_ENUMERATE | DESKTOP.DESKTOP_HOOKCONTROL | DESKTOP.DESKTOP_JOURNALPLAYBACK |
DESKTOP.DESKTOP_JOURNALRECORD);
IntPtr old = user32.GetThreadDesktop(kernel32.GetCurrentThreadId());
if (old == null) return;
IntPtr input = user32.OpenInputDesktop(0, false, access);
if (input == null) return;
SECURITY_ATTRIBUTES s = new SECURITY_ATTRIBUTES();
IntPtr newdesk = user32.CreateDesktop("newdesktop", IntPtr.Zero, IntPtr.Zero, 0,access, ref s);
if (newdesk == null) { user32.CloseDesktop(input); return; }
user32.SetThreadDesktop(newdesk);
user32.SwitchDesktop(newdesk);
MessageBox.Show("新しいデスクトップ");
user32.SetThreadDesktop(old);
user32.SwitchDesktop(old);
user32.CloseDesktop(newdesk);
user32.CloseDesktop(input);
■No28908に返信(meruruさんの記事)
> 新しいデスクトップの作成はできたのですがメッセージボックス(MessageBox.Showの方)をしたところ元のデスクトップのほうに表示されてしまい、元のデスクトップに戻れなくなってしまいました

MessageBox 自体も API の方を呼んだらどうなりますか?


MessageBox.Show はメインウィンドウやアプリケーション内のアクティブウィンドウなど、なるべく親となるウィンドウを指定するように動きます。
この挙動によって、元のデスクトップにあるウィンドウが親となるために、元のデスクトップに表示されているのではないかと推測しました。
C のサンプルは API を呼んでおり、親となるウィンドウを NULL、つまり「なし」と指定していることから、MessageBox.Show とは異なる動きだと考えられます。

# MessageBox.Show で null 渡しても API と同じにはならないので注意。
だめです;;
古い方のデスクトップにメッセージボックスができてしまいました
メッセージボックスもマネージじゃなくネイティブのほうを使用しました
これでもダメとなるとほかの方法を使用してもダメかも・・・
static class Program
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
const DESKTOP access = (DESKTOP.WINSTA_ALL_ACCESS);
IntPtr old = user32.GetThreadDesktop(kernel32.GetCurrentThreadId());
if (old == null) return;
IntPtr input = user32.OpenInputDesktop(0, false, access);
if (input == null) return;
SECURITY_ATTRIBUTES s = new SECURITY_ATTRIBUTES();
IntPtr newdesk = user32.CreateDesktop("newdesktop", IntPtr.Zero, IntPtr.Zero, 0, access, ref s);
if (newdesk == null) { user32.CloseDesktop(input); return; }
user32.SetThreadDesktop(newdesk);
user32.SwitchDesktop(newdesk);
user32.MessageBox(IntPtr.Zero, "マネージコードデスクトップ", "新しいウィンドウ", MB.OK | MB.ICONINFORMATION);
user32.SetThreadDesktop(old);
user32.SwitchDesktop(old);
user32.CloseDesktop(newdesk);
user32.CloseDesktop(input);
}
}
どうやら関数の中でエラーが発生してたみたいです
スレッドの切り替えやデスクトップの切り替えのときにすべてFALSEを返しました
しかたないのではじめてのC++の勉強ということでC++をします
まだ解決してないので解決済みにはしません。
何回かまた見に来ます
2011/08/19(Fri) 23:25:09 編集(投稿者)

■No28915に返信(meruruさんの記事)
> どうやら関数の中でエラーが発生してたみたいです
> スレッドの切り替えやデスクトップの切り替えのときにすべてFALSEを返しました

そうであれば、DllImport 属性で SetLastError を指定しておいて、失敗したときのエラーコードを GetLastWin32Error で確かめてください。
C++ を試すのは、エラーコードを元に何が悪いか調べてからでも遅くはありませんよ。
http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.dllimportattribute.setlasterror(v=VS.100).aspx
2011/08/21(Sun) 14:00:14 編集(投稿者)
2011/08/21(Sun) 14:00:08 編集(投稿者)

ごめんなさい!
ちょっと簡単な質問します!
デスクトップ関係の関数を色々動かしたところ
すべてfalseが返ってきました

これは単純な考えで失敗したと見ればいいのでしょうか
それともC#とWinAPIの考えは違ってFLASEは成功したと見ればいいのでしょうか
後もうひとつあって、C#ではどのタイミングにウィンドウクラスを登録しているのでしょうか
情報によればウィンドウクラスを登録するとデスクトップ関係さまざまな関数で失敗するそうです

後ちょっと違う質問なんですが
WinAPIでHWNDに引数に対してNULLを指定するところがありますが
C#ではIntPtrにnullはできません
C#のIntPtr.ZeroはWinAPIのNULLでいいのでしょうか


あと現在C++で開発しててC#とぜんぜん違う仕様に困惑中です
新しいデスクトップにウィンドウを表示することはできました!
しかし新しいデスクトップを閉じれずにハンドルが残ったままですが

DOBON.NET | プログラミング道 | プログラミング掲示板