当我调用EnumDesktopWindows_GetProcIDWindowList时,我遇到了一个非常奇怪的问题......它只是在枚举桌面窗口的过程中停止了!
我希望从这些关于程序员的丰富知识中获得的,是调试枚举停止原因的一些方面。
解决问题...这只是在计算机重新启动并首次登录后才发生。如果用户注销然后重新登录,则在初始登录后,此代码运行正常。 (那个问题真是太奇怪了)
换句话说:
1次重启
2登录
3个枚举停止
4注销(枚举停止的应用程序也停止)
5登录(应用程序重启)
6枚举现在有效
我还应该声明:Windows服务创建在用户登录时执行枚举的应用程序。该应用程序是一个具有隐藏窗口的winform
private ProcessStartInfo StartProcessAsCurrentUser_UnderServiceContext(string appPath, SessionInformation si)
{
LogIt(BaseLogger.LL_2, string.Format("StartProcessAsCurrentUser_UnderServiceContext"));
string cmdLine = null;
string workDir = null;
ProcessStartInfo retval = new ProcessStartInfo();
retval.Disposition = eAgentUIDisposition.Error;
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
int nError = 0;
try
{
bool bCallGetSessionUserToken = true;
if (System.Diagnostics.Debugger.IsAttached)
{
// GetSessionUserToken eventually calls WTSQueryUserToken..
// which is good when this process is running under a service context,
// but when it's running under the debugger (user context)
// WTSQueryUserToken fails with error 1314: A required privilege is not held by the client.
bCallGetSessionUserToken = false;
}
if(bCallGetSessionUserToken)
{
if (!GetSessionUserToken(si.SessionID, ref hUserToken))
{
string error = string.Format("ERROR : GetSessionUserToken failed ( error has already been logged ).");
LogIt(BaseLogger.LL_Error, error);
retval.Disposition = eAgentUIDisposition.Error_UserToken;
return retval;
}
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE;
startInfo.wShowWindow = (short)(SW.SW_SHOW);
startInfo.lpDesktop = "winsta0\\default";
if (!localNative.CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
nError = Marshal.GetLastWin32Error();
string error = string.Format("ERROR : code '{0}' CreateEnvironmentBlock failed.", nError);
LogIt(BaseLogger.LL_Error, error);
retval.Disposition = eAgentUIDisposition.Error_EnvironmentBlock;
return retval;
}
if (!localNative.CreateProcessAsUser(
hUserToken, // client's access token
appPath, // file to execute
cmdLine, // Command Line
IntPtr.Zero, // pointer to process SECURITY_ATTRIBUTES
IntPtr.Zero, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
pEnv, // pointer to new environment block
workDir, // name of current working directory
ref startInfo, // pointer to STARTUPINFO structure
out procInfo) // receives information about new process
)
{
nError = Marshal.GetLastWin32Error();
string error = string.Format("ERROR : code '{0}' CreateProcessAsUser failed. Could NOT create process", nError);
LogIt(BaseLogger.LL_Error, error);
retval.Disposition = eAgentUIDisposition.Error_ProcessAsUser;
return retval;
}
}
finally
{
localNative.CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
localNative.DestroyEnvironmentBlock(pEnv);
}
localNative.CloseHandle(procInfo.hThread);
localNative.CloseHandle(procInfo.hProcess);
}
retval.Disposition = eAgentUIDisposition.Started;
retval.ProcID = procInfo.dwProcessId;
retval.SessionID = si.SessionID;
retval.User = si.User;
LogIt(BaseLogger.LL_2, string.Format("StartProcessAsCurrentUser_UnderServiceContext returning '{0}'", si));
return retval;
}
隐藏的应用程序运行此代码:
public static Dictionary<uint, iDesktopWindow> EnumDesktopWindows_GetProcIDWindowList(List<string> systemIgnoredWindows, iTitleModifier iTM)
{
Dictionary<uint, iDesktopWindow> retval = new Dictionary<uint, iDesktopWindow>();
int nZorder = -1;
InternalInterOp.EnumDelegate filter = delegate (IntPtr hWnd, int lParam)
{
bool include = false;
include = InternalInterOp.IsWindowVisible(hWnd);
if (!include)
{
return true; // get next window
}
nZorder++;
if (include)
{
string temp = GetCaptionOfWindow(hWnd, iTM);
if (string.IsNullOrEmpty(temp))
{
return true;
}
foreach(string ignore in systemIgnoredWindows)
{
if( temp.ToLower() == ignore.ToLower() )
{
return true;
}
}
}
if (include)
{
uint tempProcID = GetProcessID(hWnd);
if (!retval.ContainsKey(tempProcID))
{
DesktopWindow dw = new DesktopWindow();
dw.ZOrder = (uint)nZorder;
dw.ProcID = tempProcID;
dw.hWnd = hWnd;
retval.Add(dw.ProcID, dw);
}
}
return true;
};
bool enumRetval = false;
try
{
enumRetval = InternalInterOp.EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero);
}
catch(Exception ex)
{
// exception does not get thrown... or I am not catching it ??
}
return retval;
}
以下是一些支持定义:
public delegate bool EnumDelegate(IntPtr hWnd, int lParam);
[DllImport("user32.dll", EntryPoint = "EnumDesktopWindows", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
public static uint GetProcessID(IntPtr hWnd)
{
uint retval = 0;
InternalInterOp.GetWindowThreadProcessId(hWnd, out retval);
return retval;
}
public static string GetCaptionOfWindow(IntPtr hwnd, iTitleModifier iTM)
{
string caption = "";
StringBuilder windowText = null;
try
{
int max_length = 16384;
windowText = new StringBuilder("", max_length);
InternalInterOp.GetWindowText(hwnd, windowText, max_length);
string temp = windowText.ToString();
if (!String.IsNullOrEmpty(temp) && !String.IsNullOrWhiteSpace(temp))
{
caption = temp;
// Fix for CET-217
// prevents window text of "File1" and "File1 *" from being detected as two different files
caption = iTM.Process(caption);
}
}
catch
{
caption = "";
}
finally
{
windowText = null;
}
return caption;
}
public enum eLocation
{
None = 0,
Prefix,
Suffix
}
public interface iTitleModifier
{
eLocation Location { get; }
string Indicator { get; }
void UpdateValues(iTitleModifier val);
bool Enabled { get; }
string Process(string input);
}
[Serializable]
public class TitleModifier : iTitleModifier
{
public TitleModifier()
{
Location = eLocation.None;
Indicator = "";
SetEnabled();
}
public void UpdateValues(iTitleModifier tm)
{
Location = tm.Location;
Indicator = tm.Indicator;
}
private eLocation _Location { get; set; }
public eLocation Location
{
get
{
return _Location;
}
set
{
_Location = value;
SetEnabled();
}
}
private string _Indicator { get; set; }
public string Indicator
{
get
{
return _Indicator;
}
set
{
_Indicator = value;
SetEnabled();
}
}
private void SetEnabled()
{
bool bLocationSet = Location != eLocation.None;
bool bHasValue = !string.IsNullOrEmpty(Indicator);
Enabled = bLocationSet && bHasValue;
}
[XmlIgnore]
public bool Enabled { get; private set; }
public string Process(string input)
{
string retval = input;
if (Enabled)
{
// I made the _process function so testing of this can be as "simple"
// as commenting this line out recompiling,
// then running the activity monitor tester
retval = _process(input);
}
return retval;
}
private string _process(string input)
{
string retval = input;
int nLen = Indicator.Length;
if (Location == eLocation.Prefix)
{
if (input.StartsWith(Indicator))
{
retval = input.Substring(nLen, input.Length - nLen);
}
}
else if (Location == eLocation.Suffix)
{
if (input.EndsWith(Indicator))
{
retval = input.Substring(0, input.Length - nLen);
}
}
else
{
// leave it be...
}
return retval;
}
public override string ToString()
{
string retval = "";
if (Enabled)
{
retval = string.Format(" TM {0} {1}", Location, Indicator);
}
return retval;
}
}
public interface iDesktopWindow
{
IntPtr hWndParent { get; }
IntPtr hWnd { get; }
uint ProcID { get; }
uint ZOrder { get; set; }
}
public class DesktopWindow : iDesktopWindow
{
public DesktopWindow()
{
hWndParent = IntPtr.Zero;
hWnd = IntPtr.Zero;
ProcID = 0;
ZOrder = 0;
}
public IntPtr hWndParent { get; set; }
public IntPtr hWnd { get; set; }
public uint ProcID { get; set; }
public uint ZOrder { get; set; }
public override string ToString()
{
string retval = ""; ;
retval = string.Format("procID:({0}) zorder:{1} hwnd:'{2}' parent '{3}'", ProcID, ZOrder, hWnd, hWndParent);
return retval;
}
}