M a r k P i t . c o m

"After three days without programming, life becomes meaningless." - The Tao of Programming

Presentation on WSE 2.0

clock April 20, 2005 09:20 by author Mark

I went to a presentation last night at the AZ ASP.NET User Group meeting. It was on Web Services Security with WSE 2.0. WSE is something that I have heard about, maybe even read a little about, but I haven't taken the time to really learn about it so I figured this would be a good way to get into it. The speaker was $g(Michele Leroux Bustamante) and she did an excellent job. I didn't nod off at all :) The timing on this was perfect. I was just writing a web service that I wanted to secure and I started down the road of using Forms Authentication in ASP.NET. That just turns out to be a big pain. WSE looks like it handles the problem quite nicely.

By the way, if anyone didn't know, the guy on her t-shirt is Bob Dobbs from the Church of the Subgenius.
 



Free of Defects

clock April 20, 2005 08:56 by author Mark
 I was reading a mailing list that I subscribe to when I came across a job posting. In the "Job Responsibilites" I found this gem:
Design, develop, and validate performance of  work to ensure that any software release is free of defects and does not require an additional release to correct defects.
If they find someone who can do that, they should pay that person millions of dollars!



HDTV Sound

clock April 12, 2005 22:21 by author Mark
I have noticed over the past few weeks that there is something wrong with the sound on our Phoenix ABC affiliate's HD broadcast. When a network show like Lost or Alias is on, it sounds like the audio is inside a tube. Kinda of a metallic ring to it almost. When advertisements or local programming are on it sounds fine. I don't hear this on any other channels. I wonder what is going on. I wonder if anyone else is hearing it.


Cherry OS

clock April 12, 2005 22:06 by author Mark
It's funny how all of a sudden Cherry OS turned into the Cherry Open Source Project. Gee, is it maybe because they are just re-packaging this project's code?


Why I don't use MSN Spaces

clock April 12, 2005 07:22 by author Mark

Looks like MSN Spaces is having some troubles today. It would drive me nuts not to be able to go see what's going wrong and fix it!



Conversion to dasBlog

clock April 2, 2005 01:39 by author Mark
Well, I finally bit the bullet and converted from .Text to dasBlog. Why did I convert? I didn't want to upgrade from .Text to Community Server. It just seems like overkill for my site. I don't need forums or support for multiple blogs. I also wanted to remove the dependency on SQL Server. I used DotText2DasBlog to import my posts. It worked really well!


Printing the .Net TreeView Control

clock April 2, 2005 00:30 by author Mark

Sample Image - PrintTreeView.gif

Introduction

I looked and looked for�sample code to print TreeView controls in C#. I�couldn't find anything that did exactly what I needed, so I broke down and wrote it myself!�

Background

During my search for a printing sample, I came across this article by Koay Kah Hoe, which presents a solution in C++. It gave me a few ideas and after finding�some information on Usenet about getting an image of a control, I was ready to code.�

Using the code

In order to print�the entire TreeView, the size of the area of all visible nodes has to be calculated and then the tree must be resized to accommodate the contents. This is all handled in the PrepareTreeImage method of the PrintUtility class.

				1:     
				private
				void PrepareTreeImage(TreeView tree){

2: _scrollBarWidth = tree.Width - tree.ClientSize.Width;
3: _scrollBarHeight = tree.Height - tree.ClientSize.Height;
4: tree.Nodes[0].EnsureVisible();
5: int height = tree.Nodes[0].Bounds.Height;
6: this._nodeHeight = height;
7: int width = tree.Nodes[0].Bounds.Right;
8: TreeNode node = tree.Nodes[0].NextVisibleNode;
9: while(node != null){
10: height += node.Bounds.Height;
11: if(node.Bounds.Right > width){
12: width = node.Bounds.Right;
13: }
14: node = node.NextVisibleNode;
15: }
16: //keep track of the original tree settings
17: int tempHeight = tree.Height;
18: int tempWidth = tree.Width;
19: BorderStyle tempBorder = tree.BorderStyle;
20: bool tempScrollable = tree.Scrollable;
21: TreeNode selectedNode = tree.SelectedNode;
22: //setup the tree to take the snapshot
23: tree.SelectedNode = null;
24: DockStyle tempDock = tree.Dock;
25: tree.Height = height + _scrollBarHeight;
26: tree.Width = width + _scrollBarWidth;
27: tree.BorderStyle = BorderStyle.None;
28: tree.Dock = DockStyle.None;
29: //get the image of the tree
30: this._controlImage = GetImage(tree.Handle, tree.Width, tree.Height);
31: //reset the tree to its original settings
32: tree.BorderStyle = tempBorder;
33: tree.Width = tempWidth;
34: tree.Height = tempHeight;
35: tree.Dock = tempDock;
36: tree.Scrollable = tempScrollable;
37: tree.SelectedNode = selectedNode;
38: //give the window time to update
39: Application.DoEvents();
40: }
41:
42:

When it is time to print the resulting image, there is some calculation to do to divide the image up into sections of the proper size to fit on the printed page. This is handled in the printDoc_PrintPage method which handles the PrintPage event of the PrintDocument. This is pretty straightforward. We have to keep track of the direction we are moving in, horizontally or vertically, across the source image.�We also�must keep track of where we left off in the image when the previous page was printed.

		

				1:     
				private
				void printDoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) {

2: this._pageNumber++;
3: Graphics g = e.Graphics;
4: Rectangle sourceRect = new Rectangle(_lastPrintPosition, e.MarginBounds.Size);
5: Rectangle destRect = e.MarginBounds;
6: if((sourceRect.Height % this._nodeHeight) > 0){
7: sourceRect.Height -= (sourceRect.Height % this._nodeHeight);
8: }
9: g.DrawImage(this._controlImage, destRect, sourceRect, GraphicsUnit.Pixel);
10: //check to see if we need more pages
11: if((this._controlImage.Height - this._scrollBarHeight) > sourceRect.Bottom
12: || (this._controlImage.Width - this._scrollBarWidth) > sourceRect.Right){
13: //need more pages
14: e.HasMorePages = true;
15: }
16: if(this._currentDir == PrintDirection.Horizontal){
17: if(sourceRect.Right < (this._controlImage.Width - this._scrollBarWidth)){
18: //still need to print horizontally
19: _lastPrintPosition.X += (sourceRect.Width + 1);
20: }
21: else{
22: _lastPrintPosition.X = 0;
23: _lastPrintPosition.Y += (sourceRect.Height + 1);
24: this._currentDir = PrintDirection.Vertical;
25: }
26: }
27: elseif(this._currentDir == PrintDirection.Vertical && sourceRect.Right
28: < (this._controlImage.Width - this._scrollBarWidth)){
29: this._currentDir = PrintDirection.Horizontal;
30: _lastPrintPosition.X += (sourceRect.Width + 1);
31: }
32: else{
33: _lastPrintPosition.Y += (sourceRect.Height + 1);
34: }
35: //print footer
36: Brush brush = new SolidBrush(Color.Black);
37: string footer = this._pageNumber.ToString(System.Globalization.NumberFormatInfo.CurrentInfo);
38: Font f = new Font(FontFamily.GenericSansSerif, 10f);
39: SizeF footerSize = g.MeasureString(footer, f);
40: PointF pageBottomCenter = new PointF(e.PageBounds.Width/2, e.MarginBounds.Bottom +
41: ((e.PageBounds.Bottom - e.MarginBounds.Bottom)/2));
42: PointF footerLocation = new PointF(pageBottomCenter.X - (footerSize.Width/2),
43: pageBottomCenter.Y - (footerSize.Height/2));
44: g.DrawString(footer, f, brush, footerLocation);
45:
46: //print header
47: if(this._pageNumber == 1 && this._title.Length > 0){
48: Font headerFont = new Font(FontFamily.GenericSansSerif, 24f,
49: FontStyle.Bold, GraphicsUnit.Point);
50: SizeF headerSize = g.MeasureString(this._title, headerFont);
51: PointF headerLocation = new PointF(e.MarginBounds.Left,
52: ((e.MarginBounds.Top - e.PageBounds.Top)/2) - (headerSize.Height/2));
53: g.DrawString(this._title, headerFont, brush, headerLocation);
54: }
55: }

The PrintUtility class should be fairly easy to use from just about any�Windows Forms application. Just call either PrintTree or PrintPreviewTree, passing in your TreeView.

When I first decided to tackle the problem of printing the TreeView, I thought it was going to take quite a bit of time and code. I was really surprised once I figured out the algorithm, how simple it really is.



COM and .NET

clock April 2, 2005 00:17 by author Mark

If you are developing an addin for Outlook in C# or another .Net language, automating Outlook or even just using COM from .Net, you should be cleaning up your COM objects (duh!). But, setting them to null is not enough. You must use the System.Runtime.InteropServices.Marshal.ReleaseComObject method to remove all references to that COM object. Here's a little class that you can use so you don't have to retype the code all over the place.

using System;
using System.Runtime.InteropServices;
namespace Utils{
public class ComUtils {
public ComUtils() {

}
/// <summary>
/// Force a release of the COM objects.
/// If you are using Outlook objects, this will allow Outlook to
/// exit cleanly after you are done with it.
/// </summary>
/// <param name="comObjects">Array of COM objects to release,
/// be sure to add the objects to the array in the order you want
/// them destroyed!</param>
public static void Release(params object[] comObjects) {
try {
for(int i = 0; i<comObjects.Length;i++) {
if(comObjects[i] != null) {
try{
// loop until the reference count is zero
while(Marshal.ReleaseComObject(comObjects[i]) > 0);
}
catch(System.InvalidCastException){
// the object was not a COM object
// no big deal, just go on to the next one
}
catch(System.NullReferenceException){
// object was null, still no big deal
// go on to next one
}
finally{
comObjects[i] = null;
}
}
}
}
catch (Exception ex) {
// insert your exception handling here
}
}
}
}

Just pass in a comma separated list of your COM objects (in the order you want them released) to the Release method of this class. For example:

ComUtils.Release(outlookMailItem, outlookNameSpace, outlookApplication);

I haven't tried it, but I assume the same type of stuff applies to automating Excel or Word too.



About the author

Mark Pitman is a dad, husband and software developer. Not always in that order, but I try!



RecentComments

Comment RSS

Sign in