private void Unlocked() { LockEndTime = DateTime.Now; _locked = false; _lastWinState = WinEvntState.Unknown; TimeSpan lockedInterval = LockEndTime - LockStartTime; #if DEBUG Console.WriteLine($" ** UnLocked Writing Time: {LockEndTime} AppName: {Globals.LastWindowEvent.AppName} Title: {Globals.LastWindowEvent.WindowTitle} Project: {Globals.LastWindowEvent.DevProjectName}"); #endif var hlpr = new DHWindowEvents(AppWrapper.AppWrapper.DevTrkrConnectionString); lock (Globals.SyncLockObject) { Globals.LastWindowEvent.EndTime = LockEndTime; var row = hlpr.InsertWindowEvent(Globals.LastWindowEvent); //next, create a new LastWindowEvent // 2) create a locked window event in database string displayName; try { displayName = UserPrincipal.Current.DisplayName; } catch (Exception ex) { displayName = Environment.UserName; } var item = new WindowEvent { ID = Guid.NewGuid().ToString(), StartTime = LockStartTime, WindowTitle = AppWrapper.AppWrapper.AppName, AppName = AppWrapper.AppWrapper.AppName, ModuleName = AppWrapper.AppWrapper.AppName, //EndTime = LockEndTime, DevProjectName = AppWrapper.AppWrapper.AppName, ITProjectID = string.Empty, UserName = Environment.UserName, MachineName = Environment.MachineName, UserDisplayName = displayName }; Globals.LastWindowEvent = item; //var rows = hlpr.InsertWindowEvent(item); } WindowPolling.ResumeWindowPolling(); }
/// <summary> /// If log is null do not create a listvieew item, just log to database /// </summary> /// <param name="p"></param> /// <param name="log"></param> public WindowEvents(Process p, ListView log) { try { var now = DateTime.Now; // time window changed Log = log; var title = GetActiveWindowTitle(); #if DEBUG Debug.WriteLine("**** " + title); #endif if (title == null) { return; } var accessDenied = false; var moduleName = string.Empty; try { moduleName = p.MainModule.ModuleName; } catch (Win32Exception ex) { // process access denied b/c it is running as admin moduleName = "Process-Access Denied"; accessDenied = true; } string displayName; try { displayName = UserPrincipal.Current.DisplayName; } catch (Exception ex) { displayName = Environment.UserName; } if (Globals.LastWindowEvent == null) { Globals.StartTime = now; } TimeSpan elapsedTime = now - Globals.StartTime; Globals.StartTime = now; // current window change time var devPrjName = string.Empty; // We set some globals so the file watcher knows who is running try { _currentApp = Globals.CurrentApp = !accessDenied ? p.ProcessName : AccessDenied; } catch (Exception ex) { Debug.WriteLine(ex.Message); Globals.CurrentApp = "Unknown"; } bool writeDB = false; /* make project extraction generic with regex */ // new code ***** NOTE: THE ideMATCHES TABLE SHOULD ONLY HAVE IDES AND SSMS **** // **** WE ARE DOING THIS FOR SSMS THO NOT AN IDE B/C SO MUCH TIME IS SPENT THERE // **** AND EVEN GROUPING BY A SERVER.DBNAME MAY GIVE A CLUE TO THE DEV PROJECT IDEMatch ideMatchObject = null; //new evidence for mulltiple IDEMatch objects for the same IDE i.e., devenv // title = "Add New Item - BusinessObjects" // title = "Add Existing Item - BusinessObjects" // title = "Reference Manager - DevTrkrReports" // ssms failing to update project name here and the reason is that ide.DBUnknown is // likely not set b/c ide switches when window changes, .^. some switch must reside in globals // that will persist between window changes.. and cache updates // i think that is what the index in the match table was // about and then I forgot its purpose and removed it //NOTE: simplifying problem by updating below for whichever app when we find a new match //bool foundIDE = false; foreach (var ide in Globals.IDEMatches) { if (!accessDenied && _currentApp.ToLower() == ide.AppName) { var pat = ide.Regex; var m = Regex.Match(title, pat, RegexOptions.IgnoreCase); devPrjName = string.Empty; if (m.Success && m.Groups[ide.RegexGroupName] != null && !string.IsNullOrWhiteSpace(m.Groups[ide.RegexGroupName].Value)) { #if DEBUG if (ide.AppName == "ssms") { Debug.WriteLine(title); } #endif // we found the ide match we are looking for ideMatchObject = ide; // if we are concatinating two fields in ssms to get server.dbname if (!string.IsNullOrWhiteSpace(ide.ProjNameConcat)) { string[] concats = ide.ProjNameConcat.Split('|'); for (var i = 0; i < concats.Length; i++) { devPrjName += (i > 0 ? ide.ConcatChar : string.Empty) + m.Groups[concats[i]].Value; } } else { devPrjName = m.Groups[ide.RegexGroupName].Value; } if (!string.IsNullOrWhiteSpace(ide.ProjNameReplaces)) { string[] replaces = ide.ProjNameReplaces.Split('|'); foreach (string s in replaces) { devPrjName = devPrjName.Replace(s, string.Empty).Trim(); } } // NOTE: new logic for IDEMatch objects that have AlternateProjName // if it is not null, replace devPrjName with it b/c altho we found a project name // it is not one we want, so make it what we want (probably the same as the unknown value) // so that it will be updated when we find the projname we want... // e.g., ssms has master set so DBname = Server.master in table but new logic will be correctable // e.g. ssms "not connected" can now have its own match object and will get set to unknow until // user connects to a database which they will have to do in order to do anything in ssms if (ideMatchObject.AlternateProjName != null) { devPrjName = ideMatchObject.AlternateProjName; } // update project name in windowevents that were written with projname unknown UpdateUnknownProjectNameForIDEMatch(devPrjName, ide.AppName, ide.UnknownValue, Environment.MachineName, Environment.UserName); // since we have found and processed the ide that we wanted, get out writeDB = true; goto EndOfGenericCode; } else /// if (m.Success && string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) { // ide has no project open yet set as unknown devPrjName = ide.UnknownValue;; //ide.DBUnknown = true; writeDB = true; continue; // loop to see if another IDEMatch row will get the projectname } // *** removing so we loop to see if another IDEMatch will get the PrjName ...goto EndOfGenericCode; } } // if at this point we did not find an idematch just an unknown window EndOfGenericCode: // end new code #region old code /* strt of old cod * if (!accessDenied && Globals.CurrentApp == AppWrapper.AppWrapper.devenv) * { * var patt = "(?<PrjName>.*?)(?<spacer> - )*Microsoft Visual Studio|Microsoft Visual Studio"; * var m = Regex.Match(title, patt); * devPrjName = string.Empty; * if (m.Success && m.Groups["PrjName"] != null && !string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) * { * devPrjName = m.Groups["PrjName"].Value.Replace("(Running)", string.Empty).Replace("(Debugging)", string.Empty).Trim(); * if (Globals.VSUnknowns) * { * Globals.VSUnknowns = false; * UpdateUnknownProjectNameinVSCode(devPrjName, AppWrapper.AppWrapper.devenv, AppWrapper.AppWrapper.VSUnknown); * } * } * else // regex failed to get prjname * { * /* this is one place where project name can be set to devenv * and should not be * //devPrjName = p.ProcessName; * devPrjName = AppWrapper.AppWrapper.VSUnknown; // "devenvUnKnown"; * Globals.VSUnknowns = true; * } * } * else if (!accessDenied && Globals.CurrentApp == AppWrapper.AppWrapper.VSCode) * { * // we are in VSCode * var pattVSCode = "^(?<FileName>.*?) - (?<PrjName>.*?) - Visual Studio Code|Welcome - Visual Studio Code|Open Folder"; * var m = Regex.Match(title, pattVSCode); * devPrjName = string.Empty; * if (m.Success && m.Groups["PrjName"] != null && !string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) * { * devPrjName = m.Groups["PrjName"].Value; * if (Globals.VSCodeUnknowns) * { * Globals.VSCodeUnknowns = false; * UpdateUnknownProjectNameinVSCode(devPrjName, Globals.CurrentApp, AppWrapper.AppWrapper.VSCodeUnknown); * } * } * else if (m.Success && string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) * { * // in vscode the * // developer has not opened a folder yet so mark * // the project name unknown until VSCode opens a folder and then * // we can update the database records * devPrjName = AppWrapper.AppWrapper.VSCodeUnknown; * Globals.VSCodeUnknowns = true; * } * else * { * devPrjName = AppWrapper.AppWrapper.VSCodeUnknown; * Globals.VSCodeUnknowns = true; * } * } * else * { * // current app is not VS or VSCode we will only be able to determine * // the project name if this app saves a file to a known project path * devPrjName = !accessDenied ? p.ProcessName : AccessDenied; * if (devPrjName == "devenv") * { * devPrjName = AppWrapper.AppWrapper.VSUnknown; * Globals.VSUnknowns = true; * } * } * end of generic changes */ //appears to be so FileWatcher can pick it out to use in creating FileAnalyzer // could be set in Globals.LastWindowEvent object not in two places // below is wrong b/c it is updating the last window that we are no longer in //Globals.LastWindowEvent.DevProjectName = devPrjName; // in practice, if you do not record all events, you could later want // to see some that would not be recorded //if (title == "Window Change Log" || title == "Project Description" || p.ProcessName == "DevTracker" || p.ProcessName == "explorer") // return; #endregion //var currApp = !accessDenied ? p.ProcessName : AccessDenied; // see if we are interested in recording this window // if writeDB set, then we already know to write this window b/c of ideMatch found if (!writeDB) { var appConfig = Globals.ConfigOptions.Find(x => x.Name == "RECORDAPPS"); if (appConfig != null) { switch (appConfig.Value) { case "A": writeDB = true; break; case "S": var interestingApp = Globals.NotableApplications.Find(o => o.AppName.ToLower() == _currentApp.ToLower()); writeDB = (interestingApp != null); break; } } } if (_currentApp.ToLower() == "explorer") { writeDB = false; // forget } // if we are writing this window, and devProjectName not set yet // see if a known project name is being worked on by a non IDE //TODO in a large shop this may be time consuming if (writeDB && string.IsNullOrWhiteSpace(devPrjName)) { devPrjName = IsProjectInNonIDETitle(title); } WindowEvent item; /* there are other threads, FileWatcher, changing this object * and we want no conflict */ if (Globals.LastWindowEvent != null) { lock (Globals.LastWindowEvent) { item = Globals.LastWindowEvent; item.EndTime = now; Globals.StartTime = now; if (writeDB) { var hlpr = new DHWindowEvents(AppWrapper.AppWrapper.DevTrkrConnectionString); if (item.DevProjectName.Equals("devenv")) { Debug.WriteLine(item.DevProjectName); } if (ideMatchObject != null && !ideMatchObject.IsIde && !devPrjName.ToLower().Contains(".sql")) { // if next line true if ((!string.IsNullOrWhiteSpace(ideMatchObject.AlternateProjName) && devPrjName == ideMatchObject.AlternateProjName) || devPrjName == ".") { Debug.WriteLine(devPrjName); } else { CheckForInsertingNewProjectPath(devPrjName, ideMatchObject.UnknownValue, Environment.UserName, Environment.MachineName, ideMatchObject.AppName); } } int rows; if (_currentApp.ToLower() == "explorer") { Debug.WriteLine("Dont write explorer"); } rows = hlpr.InsertWindowEvent(item); } } } var appNName = !accessDenied ? p.ProcessName : AccessDenied; item = new WindowEvent { ID = Guid.NewGuid().ToString(), StartTime = now, WindowTitle = title, AppName = appNName, ModuleName = moduleName, EndTime = DateTime.MinValue, DevProjectName = devPrjName, ITProjectID = string.Empty, UserName = Environment.UserName, MachineName = Environment.MachineName, UserDisplayName = displayName }; Globals.LastWindowEvent = item; const string comma = ","; #if DEBUG Debug.Write("*******" + title + comma + _startTime.ToString("HH:mm:ss") + comma + item.EndTime.ToString("HH:mm:ss") + comma + item.AppName + comma + item.ModuleName + comma + devPrjName + Environment.NewLine); #endif } catch (Exception ex) { Debug.Print(ex.Message); } }
//NOTE: new constructor public WindowEvents(/* blank constructor to process the queue WinEventProcesss p, ListView log*/) { try { WinEventProcesss wep; TopOfCode: // get a queue item if it exists while (true) { lock (Globals.WinEventQueue) { if (Globals.WinEventQueue.Count.Equals(0)) { Globals.WindowEventThreadRunning = false; return; } wep = Globals.WinEventQueue.Peek(); Globals.WinEventQueue.Dequeue(); break; } } var now = wep.Starttime; // time window changed var title = wep.MyWindowEvent.WindowTitle; #if DEBUG Debug.WriteLine("**** " + title); #endif if (title == null) { return; } var accessDenied = false; var moduleName = wep.MyWindowEvent.ModuleName; string displayName = wep.MyWindowEvent.UserDisplayName; var devPrjName = string.Empty; // We set some globals so the file watcher knows who is running _currentApp = wep.MyWindowEvent.AppName; bool writeDB = false; /* make project extraction generic with regex */ // new code ***** NOTE: THE ideMATCHES TABLE SHOULD ONLY HAVE IDES AND SSMS **** // **** WE ARE DOING THIS FOR SSMS THO NOT AN IDE B/C SO MUCH TIME IS SPENT THERE // **** AND EVEN GROUPING BY A SERVER.DBNAME MAY GIVE A CLUE TO THE DEV PROJECT IDEMatch ideMatchObject = null; //new evidence for mulltiple IDEMatch objects for the same IDE i.e., devenv // title = "Add New Item - BusinessObjects" // title = "Add Existing Item - BusinessObjects" // title = "Reference Manager - DevTrkrReports" // ssms failing to update project name here and the reason is that ide.DBUnknown is // likely not set b/c ide switches when window changes, .^. some switch must reside in globals // that will persist between window changes.. and cache updates // i think that is what the index in the match table was // about and then I forgot its purpose and removed it //NOTE: simplifying problem by updating below for whichever app when we find a new match //bool foundIDE = false; foreach (var ide in Globals.IDEMatches) { if (!accessDenied && _currentApp.ToLower() == ide.AppName) { var pat = ide.Regex; var m = Regex.Match(title, pat, RegexOptions.IgnoreCase); devPrjName = string.Empty; if (m.Success && m.Groups[ide.RegexGroupName] != null && !string.IsNullOrWhiteSpace(m.Groups[ide.RegexGroupName].Value)) { #if DEBUG if (ide.AppName == "ssms") { Debug.WriteLine(title); } #endif // we found the ide match we are looking for ideMatchObject = ide; // if we are concatinating two fields in ssms to get server.dbname if (!string.IsNullOrWhiteSpace(ide.ProjNameConcat)) { string[] concats = ide.ProjNameConcat.Split('|'); for (var i = 0; i < concats.Length; i++) { devPrjName += (i > 0 ? ide.ConcatChar : string.Empty) + m.Groups[concats[i]].Value; } } else { devPrjName = m.Groups[ide.RegexGroupName].Value; } if (!string.IsNullOrWhiteSpace(ide.ProjNameReplaces)) { string[] replaces = ide.ProjNameReplaces.Split('|'); foreach (string s in replaces) { devPrjName = devPrjName.Replace(s, string.Empty).Trim(); } } // NOTE: new logic for IDEMatch objects that have AlternateProjName // if it is not null, replace devPrjName with it b/c altho we found a project name // it is not one we want, so make it what we want (probably the same as the unknown value) // so that it will be updated when we find the projname we want... // e.g., ssms has master set so DBname = Server.master in table but new logic will be correctable // e.g. ssms "not connected" can now have its own match object and will get set to unknow until // user connects to a database which they will have to do in order to do anything in ssms if (ideMatchObject.AlternateProjName != null) { devPrjName = ideMatchObject.AlternateProjName; } // update project name in windowevents that were written with projname unknown UpdateUnknownProjectNameForIDEMatch(devPrjName, ide.AppName, ide.UnknownValue, Environment.MachineName, Environment.UserName); // since we have found and processed the ide that we wanted, get out writeDB = true; goto EndOfGenericCode; } else /// if (m.Success && string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) { // ide has no project open yet set as unknown devPrjName = ide.UnknownValue;; //ide.DBUnknown = true; writeDB = true; continue; // loop to see if another IDEMatch row will get the projectname } // *** removing so we loop to see if another IDEMatch will get the PrjName ...goto EndOfGenericCode; } } // if at this point we did not find an idematch just an unknown window EndOfGenericCode: // end new code // see if we are interested in recording this window // NOTE: we may always want to write the window to DB b/c the company may want to know every app being used // especially if we want to run the Developer(user) Detail Report // if writeDB set, then we already know to write this window b/c of ideMatch found if (!writeDB) { var appConfig = Globals.ConfigOptions.Find(x => x.Name == "RECORDAPPS"); if (appConfig != null) { switch (appConfig.Value) { case "A": writeDB = true; break; case "S": var interestingApp = Globals.NotableApplications.Find(o => o.AppName.ToLower() == _currentApp.ToLower()); writeDB = (interestingApp != null); break; } } } if (_currentApp.ToLower() == "explorer") { writeDB = false; // forget } // if we are writing this window, and devProjectName not set yet // see if a known project name is being worked on by a non IDE //TODO in a large shop this may be time consuming if (writeDB && string.IsNullOrWhiteSpace(devPrjName)) { // check to see if the window title contains a known project name devPrjName = IsProjectInNonIDETitle(title); } else { goto TopOfCode; } WindowEvent item; /* Here, we are going to record the window in db * there are other threads, FileWatcher, changing this object * and we want no conflict */ if (Globals.LastWindowEvent != null) { lock (Globals.LastWindowEvent) { item = Globals.LastWindowEvent; item.EndTime = now; Globals.StartTime = now; if (writeDB) { var hlpr = new DHWindowEvents(AppWrapper.AppWrapper.DevTrkrConnectionString); if (item.DevProjectName.Equals("devenv")) { Debug.WriteLine(item.DevProjectName); } if (ideMatchObject != null && !ideMatchObject.IsIde && !devPrjName.ToLower().Contains(".sql")) { // if next line true if ((!string.IsNullOrWhiteSpace(ideMatchObject.AlternateProjName) && devPrjName == ideMatchObject.AlternateProjName) || devPrjName == ".") { Debug.WriteLine(devPrjName); } else { if ("Connect.to_Repor._DevTrack.".Contains(devPrjName) || devPrjName.EndsWith(".")) { Debug.WriteLine("bad project name"); } else { CheckForInsertingNewProjectPath(devPrjName, ideMatchObject.UnknownValue, Environment.UserName, Environment.MachineName, ideMatchObject.AppName); } } } int rows; if (_currentApp.ToLower() == "explorer") { Debug.WriteLine("Dont write explorer"); } rows = hlpr.InsertWindowEvent(item); } } } const string comma = ","; #if DEBUG Debug.Write("******* " + title + comma + _startTime.ToString("HH:mm:ss") + comma + wep.MyWindowEvent.EndTime.ToString("HH:mm:ss") + comma + wep.MyWindowEvent.AppName + comma + wep.MyWindowEvent.ModuleName + comma + devPrjName + Environment.NewLine); #endif goto TopOfCode; // check for more } catch (Exception ex) { Debug.Print(ex.Message); } }
/// <summary> /// NOTE: You can put breakpoints in here, but if you do, then writing becomes iffy in spite of /// all that I have done to queue and thread, there are still issues in debugging /// b/c stopping in here changes the window event /// </summary> public WindowEvents() { WinEventProcesss wep; TopOfCode: try { // get a queue item if it exists while (true) { lock (Globals.SyncLockObject) { if (Globals.WinEventQueue.Count.Equals(0)) { Globals.WindowEventThreadRunning = false; return; } wep = Globals.WinEventQueue.Peek(); Globals.WinEventQueue.Dequeue(); break; } } var now = wep.Starttime; // time window changed var title = wep.MyWindowEvent.WindowTitle; if (string.IsNullOrWhiteSpace(title)) { return; } var accessDenied = false; var moduleName = wep.MyWindowEvent.ModuleName; string displayName = wep.MyWindowEvent.UserDisplayName; var devPrjName = string.Empty; var syncId = string.Empty; // We set some properties so the file watcher knows who is running _currentApp = wep.MyWindowEvent.AppName.ToLower(); bool writeDB = false; /* make project extraction generic with regex */ // new code ***** NOTE: THE ideMATCHES TABLE SHOULD ONLY HAVE IDES AND SSMS (DBMGRs) **** // **** WE ARE DOING THIS FOR SSMS THO NOT AN IDE B/C SO MUCH TIME IS SPENT THERE // **** AND EVEN GROUPING BY A SERVER.DBNAME MAY GIVE A CLUE TO THE DEV PROJECT IDEMatch ideMatchObject = null; // ssms failing to update project name here and the reason is that ide.DBUnknown is // likely not set b/c ide switches when window changes, .^. some switch must reside in globals // that will persist between window changes.. and cache updates // i think that is what the index in the match table was // about and then I forgot its purpose and removed it //NOTE: cfp.GetProjectName also sets writeDB base on multiple checks // including the config option RECORDAPPS so the decision whether // to record this window is made there var cfp = new CheckForProjectName(); Tuple <string, IDEMatch, bool, string> cfpObject = cfp.GetProjectName(title, accessDenied, _currentApp, writeDB); devPrjName = cfpObject.Item1; writeDB = cfpObject.Item3; ideMatchObject = cfpObject.Item2; wep.MyWindowEvent.SyncID = cfpObject.Item4; // if we are writing this window, and devProjectName not set yet // see if a known project name is being worked on by a non IDE if (writeDB) { // check to see if the window title contains a known project name if (string.IsNullOrWhiteSpace(devPrjName)) { Tuple <string, string> prjObject = cfp.IsProjectInNonIDETitle(title); if (prjObject != null) { devPrjName = prjObject.Item1; wep.MyWindowEvent.SyncID = prjObject.Item2; } } } else { // one or more goto TopOfCode; } // try to get syncId from DevProjects var hlpr = new DHWindowEvents(); if (/*ideMatchObject != null && !ideMatchObject.IsDBEngine && */ !string.IsNullOrWhiteSpace(devPrjName)) { MaintainProject mp = new MaintainProject(); // bypass next line until we get fw debugged if (string.IsNullOrWhiteSpace(wep.MyWindowEvent.SyncID)) { wep.MyWindowEvent.SyncID = mp.GetProjectSyncIDForProjectName(devPrjName); //, _currentApp); } // here we should update any WindowEvents that have been created by this appname // and for this project w/o a syncid if (!string.IsNullOrWhiteSpace(wep.MyWindowEvent.SyncID)) { hlpr.UpdateWindowEventsWithSyncID(devPrjName, _currentApp, wep.MyWindowEvent.SyncID); } } /* Here, we are going to record the window in db * there are other threads, FileWatcher, changing this object * and we want no conflict */ WindowEvent item = wep.MyWindowEvent; if (item.AppName == "ApplicationFrameHost" && item.WindowTitle.Contains("Solitaire")) { item.AppName = item.WindowTitle; } if (!string.IsNullOrWhiteSpace(item.DevProjectName) && item.DevProjectName.Equals("devenv")) { _ = new LogError($"WindowEvent, Bad Project Name of 'devenv' from Title: {item.WindowTitle}", false, "WindowEvents.ctor"); } if (ideMatchObject != null && devPrjName == "DevTracker" && ideMatchObject.AppName == "ssms") { _ = new LogError($"WindowEvents, 'Devtracker' should not be the project name for ssms, Title: {item.WindowTitle}", false, "WindowEvent.ctor"); } //NOTE: 4 / 27 / 2020 discontinued this doing anything...except writing bad data notes // Window events does not have devpath and therefore is not qualified to insert a project if (ideMatchObject != null && !ideMatchObject.IsIde && !devPrjName.ToLower().Contains(".sql")) { // if next line true if (/*(!string.IsNullOrWhiteSpace(ideMatchObject.AlternateProjName) && devPrjName == ideMatchObject.AlternateProjName) || */ devPrjName == ".") { _ = new LogError($"WindowEvents, Bad Project Name: {devPrjName} from Title: {item.WindowTitle}", false, "WindowEvents.ctor"); } else { // this is a check for convoluted name going to DevProjectName if ("Connect.to_Repor._DevTrack.".Contains(devPrjName) || devPrjName.EndsWith(".")) { _ = new LogError($"WindowEvents bad project name = {devPrjName} from Title: {item.WindowTitle}", false, "WindowEvents.ctor"); } //NOTE: we should not set an unknown value in the devproject table // the way the sproc is written, this call will insert a new project with unknown path // if the project does not exist, and if it does exist, this call will not update // the path b/c this call is passing xxUnknown as the the path, // if this is the way a project gets created in DevProjects, it will only get the correct path // from the save of a project file, which only get done when a new project is created else if (string.IsNullOrWhiteSpace(devPrjName) || string.IsNullOrWhiteSpace(ideMatchObject.UnknownValue)) { _ = new LogError($"WindowEvents, Missing Data, Project: {devPrjName} Path: {ideMatchObject.UnknownValue} from Title: {item.WindowTitle}", false, "WindowEvents.ctor"); } else { // we create projects for database servers here for two reasons // 1) they don't have a path // 2) they will get no files saved with any relation to a path so FileAnalyzer won't create the project // when development of DevTracker was begun, windowevents // was the only way we had of possibly getting the project // name, but it did not, nor does it now have a way to get // the path. FileAnalyzer on the other hand has an exact way of // deriving the path to the projectFile .xxproj so Les has made // the decision of stopping what is at best doing half the job // except for database projects //Debug.WriteLine($"**** Would have checked for writing {devPrjName} to DevProjects"); if (ideMatchObject != null && ideMatchObject.IsDBEngine && devPrjName != ideMatchObject.AlternateProjName) { var mp = new MaintainProject(); DevProjPath dpp = new DevProjPath { DevProjectName = devPrjName, DevProjectPath = ideMatchObject.UnknownValue, IDEAppName = item.AppName, DatabaseProject = ideMatchObject.IsDBEngine, CountLines = false, ProjFileExt = "sql", DevSLNPath = string.Empty, GitURL = devPrjName, Machine = Environment.MachineName, UserName = Environment.UserName, CreatedDate = DateTime.Now }; item.SyncID = mp.CheckForInsertingNewProjectPath(dpp); } } } } if (item.AppName == "ssms" && item.DevProjectName == "Microsoft") { _ = new LogError($"WindowEvents, Bad Project name 'Microsoft' from Title: {item.WindowTitle}", false, "WindowEvents.ctor"); } item.DevProjectName = devPrjName; hlpr = new DHWindowEvents(); int rows = hlpr.InsertWindowEvent(item); goto TopOfCode; // check for more queue entries } catch (Exception ex) { _ = new LogError(ex, false, "WindowEvents.ctor"); } goto TopOfCode; }
/// <summary> /// If log is null do not create a listvieew item, just log to database /// </summary> /// <param name="p"></param> /// <param name="log"></param> public WindowEvents(Process p, ListView log) { try { var now = DateTime.Now; // time window changed Log = log; var title = GetActiveWindowTitle(); #if DEBUG Debug.WriteLine("**** " + title); #endif if (title == null) { return; } var accessDenied = false; var moduleName = string.Empty; try { moduleName = p.MainModule.ModuleName; } catch (Win32Exception ex) { // process access denied b/c it is running as admin moduleName = "Process-Access Denied"; accessDenied = true; } string displayName; try { displayName = UserPrincipal.Current.DisplayName; } catch (Exception ex) { displayName = Environment.UserName; } if (Globals.LastWindowEvent == null) { Globals.StartTime = now; } TimeSpan elapsedTime = now - Globals.StartTime; Globals.StartTime = now; // current window change time var devPrjName = string.Empty; // We set some globals so the file watcher knows who is running try { Globals.CurrentApp = !accessDenied ? p.ProcessName : AccessDenied; } catch (Exception ex) { Debug.WriteLine(ex.Message); Globals.CurrentApp = "Unknown"; } if (!accessDenied && Globals.CurrentApp == AppWrapper.AppWrapper.devenv) { var patt = "(?<PrjName>.*?)(?<spacer> - )*Microsoft Visual Studio|Microsoft Visual Studio"; var m = Regex.Match(title, patt); devPrjName = string.Empty; if (m.Success && m.Groups["PrjName"] != null && !string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) { devPrjName = m.Groups["PrjName"].Value.Replace("(Running)", string.Empty).Replace("(Debugging)", string.Empty).Trim(); if (Globals.VSUnknowns) { Globals.VSUnknowns = false; UpdateUnknownProjectNameinVSCode(devPrjName, AppWrapper.AppWrapper.devenv, AppWrapper.AppWrapper.VSUnknown); } } else /* regex failed to get prjname */ { /* this is one place where project name can be set to devenv * and should not be */ //devPrjName = p.ProcessName; devPrjName = AppWrapper.AppWrapper.VSUnknown; // "devenvUnKnown"; } } else if (!accessDenied && Globals.CurrentApp == AppWrapper.AppWrapper.VSCode) { // we are in VSCode var pattVSCode = "^(?<FileName>.*?) - (?<PrjName>.*?) - Visual Studio Code|Welcome - Visual Studio Code|Open Folder"; var m = Regex.Match(title, pattVSCode); devPrjName = string.Empty; if (m.Success && m.Groups["PrjName"] != null && !string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) { devPrjName = m.Groups["PrjName"].Value; if (Globals.VSCodeUnknowns) { Globals.VSCodeUnknowns = false; UpdateUnknownProjectNameinVSCode(devPrjName, Globals.CurrentApp, AppWrapper.AppWrapper.VSCodeUnknown); } } else if (m.Success && string.IsNullOrWhiteSpace(m.Groups["PrjName"].Value)) { // in vscode the // developer has not opened a folder yet so mark // the project name unknown until VSCode opens a folder and then // we can update the database records devPrjName = "UnKnown"; Globals.VSCodeUnknowns = true; } else { devPrjName = AppWrapper.AppWrapper.VSCodeUnknown; Globals.VSCodeUnknowns = true; } } else { // current app is not VS or VSCode we will only be able to determine // the project name if this app saves a file to a known project path devPrjName = !accessDenied ? p.ProcessName : AccessDenied; if (devPrjName == "devenv") { devPrjName = AppWrapper.AppWrapper.VSUnknown; Globals.VSUnknowns = true; } } //appears to be so FileWatcher can pick it out to use in creating FileAnalyzer // could be set in Globals.LastWindowEvent object not in two places // below is wrong b/c it is updating the last window that we are no longer in //Globals.LastWindowEvent.DevProjectName = devPrjName; // in practice, if you do not record all events, you could later want // to see some that would not be recorded //if (title == "Window Change Log" || title == "Project Description" || p.ProcessName == "WindowChangeTracker" || p.ProcessName == "explorer") // return; var currApp = !accessDenied ? p.ProcessName : AccessDenied; // see if we are interested in recording this window var weCare = Globals.NotableApplications.Find(o => o.AppName.ToLower() == currApp.ToLower()); var writeDB = (weCare != null); if (currApp.ToLower() == "explorer") // && !title.StartsWith("File Explorer")) { writeDB = false; // forget } WindowEvent item; /* there are other threads, FileWatcher, changing this object * and we want no conflict */ if (Globals.LastWindowEvent != null) { lock (Globals.LastWindowEvent) { item = Globals.LastWindowEvent; item.EndTime = now; Globals.StartTime = now; if (writeDB) { var hlpr = new DHWindowEvents(AppWrapper.AppWrapper.DevTrkrConnectionString); if (item.DevProjectName.Equals("devenv")) { Debug.WriteLine(item.DevProjectName); } var rows = hlpr.InsertWindowEvent(item); } } } var appNName = !accessDenied ? p.ProcessName : AccessDenied; item = new WindowEvent { ID = Guid.NewGuid().ToString(), StartTime = now, WindowTitle = title, AppName = appNName, ModuleName = moduleName, EndTime = DateTime.MinValue, DevProjectName = devPrjName, ITProjectID = string.Empty, UserName = Environment.UserName, MachineName = Environment.MachineName, UserDisplayName = displayName }; Globals.LastWindowEvent = item; const string comma = ","; #if DEBUG Debug.Write("*******" + title + comma + _startTime.ToString("HH:mm:ss") + comma + item.EndTime.ToString("HH:mm:ss") + comma + item.AppName + comma + item.ModuleName + comma + devPrjName + Environment.NewLine); #endif if (Log != null && writeDB) { ListViewItem lvi = new ListViewItem(Globals.StartTime.ToString("MM/dd/yyyy HH:mm:ss")); // starttime lvi.SubItems.Add(title); // WindowTitle lvi.SubItems.Add(item.AppName); // AppName lvi.SubItems.Add(moduleName); // ModuleName lvi.SubItems.Add(TimeSpan.FromTicks(elapsedTime.Ticks).ToString()); lvi.SubItems.Add(devPrjName); lvi.SubItems.Add(""); //ID lvi.SubItems.Add(""); // desc lvi.SubItems.Add(p.StartInfo.WorkingDirectory); lvi.SubItems.Add(displayName); log.Items.Add(lvi); } } catch (Exception ex) { Debug.Print(ex.Message); } }
private void Locked() { LockStartTime = DateTime.Now; var accessDenied = false; var _currentApp = Globals.LastWindowEvent.AppName; IDEMatch ideMatchObject = null; bool writeDB = false; //_locked = true; // turn off polling while locked, so we will not see any window change while locked // therefore LastWindowEvent should be the one created below when we detect unlock WindowPolling.SuspendWindowPolling(); // Try to get the project name for the Globals.LastWindowEvent var cfp = new CheckForProjectName(); Tuple <string, IDEMatch, bool, string> cfpObject = cfp.GetProjectName(Globals.LastWindowEvent.WindowTitle, accessDenied, Globals.LastWindowEvent.AppName, writeDB); string devProjectName = cfpObject.Item1; ideMatchObject = cfpObject.Item2; writeDB = cfpObject.Item3; if (string.IsNullOrWhiteSpace(Globals.LastWindowEvent.DevProjectName)) { Globals.LastWindowEvent.DevProjectName = devProjectName; } var hlpr = new DHWindowEvents(AppWrapper.AppWrapper.DevTrkrConnectionString); lock (Globals.SyncLockObject) { // now, make it look like the current window when the lock occurs is being moved away from // by writing it to database Globals.LastWindowEvent.EndTime = LockStartTime; hlpr.InsertWindowEvent(Globals.LastWindowEvent); // next, start a new LastWindowEvent called ComputerLocked // and put it in Globals.LastWindowEvent string displayName; try { displayName = UserPrincipal.Current.DisplayName; } catch (Exception ex) { displayName = Environment.UserName; } var item = new WindowEvent { ID = Guid.NewGuid().ToString(), StartTime = LockStartTime, WindowTitle = locked, AppName = locked, ModuleName = locked, EndTime = LockEndTime, DevProjectName = locked, ITProjectID = string.Empty, UserName = Environment.UserName, MachineName = Environment.MachineName, UserDisplayName = displayName }; Globals.LastWindowEvent = item; } }