目標は
Win XP で実行されているアプリケーション (ターゲット) の不透明度を変更したいと考えています。
状況
- Windows XP に AD (アクティブ ディレクトリ) ユーザー アカウント (some-domain\username) としてログインしました。
- ターゲット アプリケーションのほとんどは、ローカル ユーザーまたは別の広告ユーザーとして実行されます。
問題と私の質問
SetWindowLong
&SetLayeredWindowAttributes
は、他のユーザー アカウントとして実行されるターゲット アプリケーションでは機能しません。ただし、同じユーザー アカウント (ログに記録されたユーザー アカウント) で実行されるターゲット アプリケーションでは機能します。
別のユーザー アカウントとして実行されている他のアプリのウィンドウの不透明度を変更するにはどうすればよいですか?
イラストアプリ
これは win フォーム アプリです (OpaciToggler.exe と呼びましょう)。2 つのボタン (btnRunSomething と btnHideThatThing) とテキスト ボックス (txtPid) があります。それと同じくらい簡単です。
btnRunSomething をクリックすると、別のユーザーとして .exe が実行されます。すべての詳細は app.config にあります。この場合、このアプリケーション (デバッグ/ビンからの OpaciToggler.exe) を別のユーザー (localComputer\user1) として実行します。
txtPid は手動の pid 入力用です。通常、タスク マネージャー (win > run > taskmgr) を開き、テストするアプリケーション (ターゲット) の pid ([プロセス] タブの下) を見つけて、ここに入力します。
btnHideThatThing をクリックすると、ターゲット アプリケーション (txtPid の pid) の不透明度が切り替わります
コード C#
これは、ターゲットアプリを呼び出す方法です。
private void btnRunSomething_Click(object sender, EventArgs e)
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.Domain = ConfigurationManager.AppSettings["StartInfoDomain"];
p.StartInfo.UserName = ConfigurationManager.AppSettings["StartInfoUserName"];
p.StartInfo.FileName = ConfigurationManager.AppSettings["StartInfoFileName"];
p.StartInfo.Arguments = ConfigurationManager.AppSettings["StartInfoArguments"];
System.String rawPassword = ConfigurationManager.AppSettings["StartInfoPassword"];
System.Security.SecureString encPassword = new System.Security.SecureString();
foreach (System.Char c in rawPassword)
{
encPassword.AppendChar(c);
}
p.StartInfo.Password = encPassword;
p.StartInfo.UseShellExecute = false;
p.Start();
}
これは私が不透明なものを呼び出そうとする方法です
private void btnHideThatThing_Click(object sender, EventArgs e)
{
// manual input pid
int pid = int.Parse(txtPid.Text);
IntPtr mwh = Process.GetProcessById(pid).MainWindowHandle;
doHideThing(mwh);
// doHideThing(Process.GetProcessById(int.Parse(txtPid.Text)).MainWindowHandle);
}
非表示メソッド
private void doHideThing(IntPtr hndl)
{
SetWindowLong(hndl, GWL_EXSTYLE, GetWindowLong(hndl, GWL_EXSTYLE) ^ WS_EX_LAYERED).ToString();
// _whatNow = Marshal.GetLastWin32Error();
SetLayeredWindowAttributes(hndl, 0, (255 * 20) / 100, LWA_ALPHA).ToString();
// _whatNow = Marshal.GetLastWin32Error();
RedrawWindow(hndl, IntPtr.Zero, IntPtr.Zero,
RedrawWindowFlags.Erase | RedrawWindowFlags.Invalidate |
RedrawWindowFlags.Frame | RedrawWindowFlags.AllChildren);
}
その他のコード
private const int GWL_EXSTYLE = -20;
private const int GWL_STYLE = -16;
private const int WS_EX_LAYERED = 0x80000;
private const int LWA_ALPHA = 0x2;
private const int LWA_COLORKEY = 0x1;
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", SetLastError = true)]
static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);
RedrawWindowFlags enum (これをどこで入手したか覚えていません)
[Flags()]
enum RedrawWindowFlags : uint
{
/// <summary>
/// Invalidates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
/// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_INVALIDATE invalidates the entire window.
/// </summary>
Invalidate = 0x1,
/// <summary>Causes the OS to post a WM_PAINT message to the window regardless of whether a portion of the window is invalid.</summary>
InternalPaint = 0x2,
/// <summary>
/// Causes the window to receive a WM_ERASEBKGND message when the window is repainted.
/// Specify this value in combination with the RDW_INVALIDATE value; otherwise, RDW_ERASE has no effect.
/// </summary>
Erase = 0x4,
/// <summary>
/// Validates the rectangle or region that you specify in lprcUpdate or hrgnUpdate.
/// You can set only one of these parameters to a non-NULL value. If both are NULL, RDW_VALIDATE validates the entire window.
/// This value does not affect internal WM_PAINT messages.
/// </summary>
Validate = 0x8,
NoInternalPaint = 0x10,
/// <summary>Suppresses any pending WM_ERASEBKGND messages.</summary>
NoErase = 0x20,
/// <summary>Excludes child windows, if any, from the repainting operation.</summary>
NoChildren = 0x40,
/// <summary>Includes child windows, if any, in the repainting operation.</summary>
AllChildren = 0x80,
/// <summary>Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive WM_ERASEBKGND and WM_PAINT messages before the RedrawWindow returns, if necessary.</summary>
UpdateNow = 0x100,
/// <summary>
/// Causes the affected windows, which you specify by setting the RDW_ALLCHILDREN and RDW_NOCHILDREN values, to receive WM_ERASEBKGND messages before RedrawWindow returns, if necessary.
/// The affected windows receive WM_PAINT messages at the ordinary time.
/// </summary>
EraseNow = 0x200,
Frame = 0x400,
NoFrame = 0x800
}
例、テスト、およびテスト結果
- win XP に domainA\ad_user1 としてログイン
- OpaciToggler.exe アプリケーションを実行します (Instance1、domainA\ad_user1 として実行)
- 次に、実行をクリックします。別の OpaciToggler.exe (Instance2) を開き、別のユーザー アカウント (localcomputer\l_user1 として実行) として実行するか、.exe を右クリックして [次のユーザーとして実行] をクリックします。
インスタンス 1
- ピッド: 1234
- 次のように実行: domainA\ad_user1
- txtPid: 5678 (インスタンス 2、機能しません)
- txtPid: 1234 (自己、動作)
- txtPid: 同じアカウントで実行される pid (例: notepad.exe、calc.exe など)
インスタンス 2
- ピッド: 5678
- 次のように実行: localcomputer\l_user1
- txtPid: 1234 (インスタンス 1、動作しません)
- txtPid: 5678 (自己、動作)
- txtPid: 同じアカウント (localcomputer\l_user1) として実行される任意の pid (例: notepad.exe、calc.exe などは機能しません!!)
繰り返しますが、私の質問
別のユーザー アカウントとして実行されている他のアプリのウィンドウの不透明度を変更するにはどうすればよいですか?
私の下手な英語に感謝し、申し訳ありません:(。