Aside from going to Seattle once a year and an occasional weekend outting, I haven’t taken a vacation since 2005. I am taking one this week!
Not sure what I am going to do with my self, but I am sure the kids will have fun.
Colby's Blog
Aside from going to Seattle once a year and an occasional weekend outting, I haven’t taken a vacation since 2005. I am taking one this week!
Not sure what I am going to do with my self, but I am sure the kids will have fun.
I have a dual monitor system. Here is how I have them setup:
The docker has to support multiple monitors, switching main monitors, and handle redocking correctly if the task bar moves. Here goes…
First, the sample app (which ships with the component) shown undocked on my monitor space:
Notice the whitespace. That is because my monitors are at different resolutions and I have them lined up so swing the mouse to and from monitors crosses the barrier between the two monitors correctly.
Dock Scenario #1 = Taskbar docked, bottom, main monitor
Passed!
Dock Scenario #2 = Taskbar docked, right, main monitor
Passed!
Dock Scenario #3 = Taskbar docked, top, main monitor
Passed
Dock Scenario #4 = Taskbar docked, left, main monitor
Passed!
Dock Scenario #5 = Taskbar docked, bottom, secondary monitor
Dock Scenario #6 = Taskbar docked, right, secondary monitor
Passed!
…Okay so you probably don’t need to see all the scenarios and you get the idea. Here is the math:
1: private void PostionLeft()
2: {
3: Point taskBarLocation = TaskBar.GetTaskBarLocation();
4: Screen taskBarScreen = Screen.FromHandle(TaskBar.GetHandle());
5: Size size = TaskBar.GetTaskBarSize();
6:
7: _Form.Left = taskBarScreen.Bounds.X + size.Width - (_BorderSize * 2);
8: _Form.Top = (taskBarScreen.WorkingArea.Height + taskBarLocation.Y + (_BorderSize * 2)) - _Form.Height;
9: }
10:
11: private void PostionTop()
12: {
13: Point taskBarLocation = TaskBar.GetTaskBarLocation();
14: Screen taskBarScreen = Screen.FromHandle(TaskBar.GetHandle());
15:
16: _Form.Top = taskBarScreen.WorkingArea.Y + _BorderSize;
17:
18: _Form.Left = (taskBarScreen.Bounds.Width + taskBarLocation.X) - (_Form.Width - (_BorderSize * 2));
19: }
20:
21: private void PostionRight()
22: {
23: Point taskBarLocation = TaskBar.GetTaskBarLocation();
24: Screen taskBarScreen = Screen.FromHandle(TaskBar.GetHandle());
25:
26: _Form.Left = (taskBarLocation.X) - (_Form.Width - (_BorderSize * 2));
27: _Form.Top = (taskBarLocation.Y + taskBarScreen.Bounds.Height + (_BorderSize * 2)) - _Form.Height;
28: }
29:
30: private void PostionBottom()
31: {
32: Point taskBarLocation = TaskBar.GetTaskBarLocation();
33: Screen taskBarScreen = Screen.FromHandle(TaskBar.GetHandle());
34:
35: _Form.Left = (taskBarScreen.Bounds.Width + taskBarLocation.X) - (_Form.Width - (_BorderSize * 2));
36:
37: _Form.Top = taskBarLocation.Y - (_Form.Height + _BorderSize);
38: }
Enjoy!
Colby
Gosh time flies. I haven’t written much for a very long time. Back in early 2007 I was writing almost every day. Not so much these days. I have been working on a new product, which will be announced later this year.. Our company, forProject Technologies, has been pushing very hard on it for almost 2.5 years. It will be a big deal, for me anyway, when we launch.
That work consumes the bulk of work time, the rest of my time is spent with my family except for a small sliver of hobby time. Over the past three years I have managed to create a few tools, some of which I am the only user while others are used internally by my company and by some friends. By the end of the summer, I hope to have these tools released on a new website I am working on, which will be announced soon as well. I think some of them may be available on my company’s site as well, but we haven’t worked that out yet.
The new website is another hobby project that is important to me not because I think the site is going to draw much traffic, but because I really need to learn some of the newest web development technologies. I spend most of my time working on backend services and Windows applications. So, the new website is where I am learning advanced java script techniques, compliant HTML/CSS (I use Expression Web, which is pretty nice), and ajax using Microsoft's ajax client library with ajax-enabled WCF web services. Pretty fun really, event if java script drives me a little bonkers sometimes.
Okay, so what I am going to do in this post is explain what each of these tools do and why I created them. First, my development environment is Visual Studio 2010 SP1 in C#, Expression 4.0, IIS 7.0 (hosted by these very cool folks), Team Foundation Server 2011 (also hosted by these very cool folks), SQL Server 2008 (hosted by…you guessed it), and TopStyle. TopStyle, by the way, has the best CSS editing environment I have encountered. And, as I was getting ready to do some screenshots for this blog, I found Sizer, which is kind of handy.
I haven’t moved to .NET 4.0 yet because some of my stuff has dependencies on SharePoint, which is not .NET 4.0 ready yet.
In no particular order… Let’s start with Queue and Performance Monitor for Project Server:
I have been working with Microsoft Project since 1996, including building quite a few products around it. In fact, that is my work currently. One of the things I did recently was build a stress/performance suite for Project Server. It involves a lot of queue operations, obviously, and the SharePoint queue viewer isn’t sufficient. So…I wrote my own.
It also supports ULS log viewing, including tracking a failed queue job’s ULS records:
Performance monitoring:
Including export of performance information:
Set thresholds and events:
Export chart to various formats:
And plenty of options:
The Windows server MMC snapin for service management is okay but not great. I wanted a tool that would give me more advanced information about services, plus the ability to create a “profile” of services that I could stop and start in bulk. Why is this useful? Well, there a great many services that are configured to run that aren’t really necessary much of the time. So, by being able to turn these off I can get a little more performance out of my machines when writing some of my server applications.
You can see the basic features in the screen shot above:
So I got to dig deeper into the service control API and even deeper into NT Services in general because some of these properties are not exposed through the BCL. But, the real fun came when I started working on the service profile feature. Here is s screenshot of the ribbon page for this feature:
The gallery on the left is just a list of all of the profiles defined. A profile is simply a set of services that I either want to start, stop, or a combination of the two in a single operation: Here is an example where I am turning off all services not required to run the OS, SharePoint, and Project Server:
When I click the Apply button, all of the selected services are put into the required state. When I apply a service profile, I have the option of creating a “restore point”, which is a record of all the services running before I applied the service profile. I can restore to that state by clicking the Restore button.
Pretty handy, with more services stuff to come later.
As I was writing about Service Manager it occurred to me that there are several characteristics and feature of all the tools I have written recently (Event Viewer/Service Manager – the rest I will retrofit to this paradigm):
Here are some screens
Launching Feedback:
Launching Info:
And you can check for updates as well:
Okay, back to the tools…
The Windows event viewer MMC snapin is pretty great, but I wanted it is lacking a few features. On particular, I would like to be able to search for key words (or multiple key words) across multiple log files… So, here is Event Viewer:
Here are the features:
None of the first four features are particularly interesting but needed just to hit the bare minimum feature set. The real useful features are search.
Along the left is a checkable tree control. I check the logs I want to search, put in my keywords (separated by a ‘,’) and click search. The engine looks through all of the checked logs and presents you the search results. In the message pane at the bottom there is also a search box, which supports incremental search (like F3 in Visual Studio).
Pretty handy!
One last feature is the engine looks at each message when you click it to see if it is HTML (a lot of our events are formatted for display in a forum other than the event viewer). If HTML is detected, the engine will render the HTML:
QuickPatch is a software servicing system I started writing back in 2007. First you define your patch, which can include replacing files, updating SharePoint solutions, running database scripts, plus a more advanced file placement feature that I will discuss elsewhere:
Configure various options, including using a “registry hint” that tells the patch application where to start looking for files to update:
Then you build the patch:
You end up with two files:
Setup is the bootstrapper and package.exe is the patch. When run, the patch applying application looks like this:
Pretty sweet!
After years of using Mark Russinovich’s debug viewer, I decided I wanted to build my own with a few more features plus do it all in .NET. Fortunately, Microsoft provides a managed debug API, which you can download here. This was started before I moved to the ribbon UI. Eventually I will return to this and update it.
Key features:
There are quite a few self-extracting executable tools out there but I wanted my own so I wrote one:
Here are the features:
If isn’t a silent, extract, run type of project, the user sees this (with sample HTML prompt content):
And then the files are extracted…
Not trying to reinvent the wheel here but I must say that some of the system tools from Microsoft are seriously Soviet looking and I prefer nicer look-and-feel so… Here is my Registry Viewer:
The best thing is the search feature:
This tool allows you to define a header for your C# source files and apply it to individual files, directories of files, or you can simply select a Visual Studio solution or project and the tool figures out what files to apply it to. Here is the user guide for more information.
Project settings page:
Limited to this weekend only, I am making 64 bit preview editions of the following tools available:
SfxCreator - A simple self-extracting executable generator
DebugViewer - An update to Mark Russinovich's DebugView, fully implemented in .NET using Microsoft's MDbg stack
Queue & Performance Monitoring Suite for Project Server - A set of utilities for monitoring Project Server's queue system, plus SharePoint’s Universal Logging System, and performance counters (including charting!).
All of these tools are very BETA at this point, and I make no guarantee about them whatsoever, and neither does my employer. My employer, by the way, keeps me plenty busy so if you want changes or additions, it may take some time. Source code is NOT available for these tools at this time.
.NET 3.5 SP1 is required before you can unpack the setup MSIs let alone run the tools.
If you have questions, please contact me through comments. If you encounter bugs, which you will, use the Help\Send Feedback feature in each tool to tell me about any problems.
Download is here (27 mb): www.mpfx.org/downloads/AllTools64bit.exe
Enjoy…
Happy Memorial Day Weekend!
This is coming out after I get the Project Server Queue Monitor out. I haven’t had much time. Pretty busy at my real job right now…
…REMEMBER TO SET THIS ON YOUR ENTRY PROC:
[MTAThread] // MDbg is MTA threaded
static void Main() { … };
I did this when I first started working on my debug viewer tool, but moved some types around and forgot to re-add it and spent an HOUR staring at my screen trying to figure out why everything stopped working…
First, just released yesterday, is the Visual Studio 2010 Service Pack I, described here. As of yesterday, it was only available to MSDN subscribers but will be broadly available on March 10th.
Since upgrading all of our projects to VS2010 this past week, I have been struggling with performance and usability issues. The most vexing problem was my mouse would simply stop working except when clicking into the solution explorer. All of the code editor windows and the main toolbar\menu would not accept mouse clicks whatsoever until the IDE was restarted. One of my colleagues recommended locating a new device drive for my mouse. I did that (and at the same time updated 18 other drivers via this wonderful little tool). I have quite a few add-ins and extensions so I started disabling them one-by-one. No luck. I was in that state this morning and I happened to move the IDE from my secondary monitor onto my primary monitor and whamo, the IDE started accepting mouse clicks. So, Tip #1, if the IDE stops accepting mouse clicks, try moving it to your primary monitor.
As you probably know, VS2010’s IDE is implemented on WPF, which brings the managed stack into the mix on a scale unlike VS2008. Many have complained that the use of WPF is a major performance hit in VS2010. I have read otherwise, but I did notice a gradual degradation of performance over time, especially with many code editor windows open. Tip # 2 is to learn the shortcut key to force VS2010 to do a garbage collection:
http://blogs.msdn.com/b/camerons/archive/2010/12/15/force-vs-to-garbage-collect.aspx
You can marginally decrease startup time and increase performance by creating a shortcut with specific command line arguments as well. Create a shortcut with these parameters:
C:\Windows\System32\cmd.exe /c start "runhigh" /high "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" /nosplash
http://weblogs.asp.net/kodali/archive/2011/01/24/visual-studio-2010-running-very-slow.aspx
There is also a performance diagnostic tool available here, but I have not been able to get it working after installing SP1
Finally, there is a good discussion of hardware requirements and other items on Stack Overflow
Project has a bug where accessing time scaled values causes an exception after a few calls. You can get around it by calling GC.Collect() and GC.WaitForPendingFinalizers() but this is super slow. Here is an example of what that looks like.
1: TimeScaleValues workValues = assignment.TimeScaleData(startDate, endDate, pjAssignmentTimescaleDataType, PjTimescaleUnit.pjTimescaleDays, 1);
2:
3: for (int i = 1; i <= days; i++)
4: {
5: try
6: {
7: string valueData = workValues[i].Value.ToString();
8:
9: if (string.IsNullOrEmpty(valueData))
10: {
11: continue;
12: }
13:
14: totalTSV = totalTSV + decimal.Parse(valueData);
15:
16: }
17: catch
18: {
19: Marshal.FinalReleaseComObject(workValues);
20: GC.Collect();
21: GC.WaitForPendingFinalizers();
22:
23: i = 1;
24: totalTSV = 0;
25:
26: workValues = assignment.TimeScaleData(startDate, endDate, pjAssignmentTimescaleDataType, PjTimescaleUnit.pjTimescaleDays, 1);
27: }
28: }
Here is a glorious hack that involves injecting a temporary macro into the Global.MPT and then calling the macro via reflection to have the TimescaleData method be called inside Project to avoid the problem.
First, inject this macro:
Public Sub GetAssignmentTSV(ByVal projectName As String, ByVal taskIndex As Long, ByVal assignmentIndex As Long, ByVal startDate As String, ByVal endDate As String, ByVal tsvType As Long, byref totalTSV As Variant) Dim tsv As TimeScaleValues Set tsv = Application.Projects(projectName).Tasks(taskIndex).Assignments(assignmentIndex).TimeScaleData(startDate, endDate, tsvType , pjTimescaleDays) Dim t As TimeScaleValue For Each t In tsv totalTSV = totalTSV + Val(t.Value) Next End Sub
By doing this (it attempts to clean up old version of the macro first):
1: private void InjectTSVMacro()
2: {
3: try
4: {
5: List<VBComponent> removeComponents = new List<VBComponent>();
6:
7: foreach (VBComponent component in _Application.VBE.VBProjects.Item(1).VBComponents)
8: {
9: int startLine = 0;
10: int startColumn = 0;
11: int endLine = 0;
12: int endColumn = 0;
13:
14: if (component.CodeModule.Find("GetAssignmentTSV", ref startLine, ref startColumn, ref endLine, ref endColumn, false, false, false))
15: {
16: removeComponents.Add(component);
17: }
18: }
19:
20: foreach (VBComponent t in removeComponents)
21: {
22: _Application.VBE.VBProjects.Item(1).VBComponents.Remove(t);
23: }
24:
25: _VBAModule = _Application.VBE.VBProjects.Item(1).VBComponents.Add(vbext_ComponentType.vbext_ct_StdModule);
26:
27: _VBAModule.CodeModule.AddFromString(Resources.TSVMacro);
28:
29: _GetTSVMethod = TSVMethod.MacroInjection;
30: }
31: catch (Exception exception)
32: {
33: QualityFx.WriteException(exception);
34: _GetTSVMethod = TSVMethod.ObjectModel;
35: }
36: }
Then call the macro like this:
1: return RunTSVMacro(_Application,
2: new object[]
3: {
4: "GetAssignmentTSV",
5: syncParameters.Project.Name,
6: task.ID,
7: assignmentId,
8: startDate.ToString(),
9: endDate.ToString(),
10: (int) pjAssignmentTimescaleDataType,
11: totalTSV
12: });
RunTSVMacro looks like this:
1: public decimal RunTSVMacro(Application application, object[] args)
2: {
3: ParameterModifier parameterModifier = new ParameterModifier(TSV_MACRO_NUMBER_OF_ARGS);
4:
5: parameterModifier[TSV_MACRO_OUT_ARG] = true;
6:
7: ParameterModifier[] parameterModifiers = { parameterModifier };
8:
9: application.GetType().InvokeMember("Run",
10: BindingFlags.Default | BindingFlags.InvokeMethod,
11: null,
12: application,
13: args,
14: parameterModifiers,
15: null,
16: null);
17:
18: return (decimal)args[TSV_MACRO_OUT_ARG];
19: }
The two constants are:
1: private const int TSV_MACRO_NUMBER_OF_ARGS = 8;
2: private const int TSV_MACRO_OUT_ARG = 7;
The RunTSVMacro method has to use the parameter modifier to let reflection know that the 7 argument is an out argument because you can call a VBA function using Project’s Run method.
Hope this helps.