星期三, 十月 31, 2007
星期二, 十月 30, 2007
今年144万应届毕业生未如期就业
Sent to you by Hudong via Google Reader:
晨报讯 (记者 罗德宏) 记者昨天从教育部获悉,2008年全国高校毕业生将超过550万人,比今年增加50多万。 据介绍,今年全国高校毕业生是495万人,比2006年增加了82万人,毕业生总量和增量都是最多的一年。到今年9月1日,全国普通高等学校的毕业生实现就业的人数是351万人....
Things you can do from here:
- Subscribe to 新闻中心-国内焦点新闻 using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
星期一, 十月 29, 2007
Lenovo Thinkpad add on for IE7 slowing things down
Hudong 通过 Google 阅读器发送给您的内容:
I just got a new Lenovo Thinkpad T61p at work and am getting it set up. Overall, it's very nice, I like the Thinkpad design, the pointing stick, and am getting used to the widescreen.
I noticed that IE7 was unusally slow, especially when opening a new tab. I always set the home page to blank to make sure everything opens fast; but for some reason everytime I would open a new tab it would take between 3-10 seconds before it would actually allow me to use the new tab. I'd never seen this before with IE7 on my old laptop or home laptop. Checked new tabs in my firefox installation and it was fine.
After a little searching I found the answer, though in a different language :) It turns out it's an add-on from Lenovo (CPwmIEBrowserHelper Object) that's causing the problem.
It turns out many others have seen the same issue. Now things are back to normal, happily browsing ... now to get my old passwords into this browser.
可从此处完成的操作:
- 使用 Google 阅读器订阅MSDN Blogs
- 开始使用 Google 阅读器,轻松地与您喜爱的所有网站保持同步更新
Are you making these 3 common ASP.NET AJAX mistakes?
Hudong 通过 Google 阅读器发送给您的内容:
Check out Dave Wards advice on Update Panels and Postabacks at Encosia HERE.
http://encosia.com/2007/10/24/are-you-making-these-3-common-aspnet-ajax-mistakes/
可从此处完成的操作:
- 使用 Google 阅读器订阅MSDN Blogs
- 开始使用 Google 阅读器,轻松地与您喜爱的所有网站保持同步更新
星期三, 十月 24, 2007
星期二, 十月 23, 2007
星期一, 十月 22, 2007
WSS 3.0中文應用範本免費下載中!
Sent to you by Hudong via Google Reader:
此外, WSS 提供了20種簡單的中文應用範本,包含人力資源, 專案管理, 銷售管理等常見應用, 免費供客戶使用. 可下載 "快速安裝套件"
下載位置:
Things you can do from here:
- on MSDN Blogs
- Subscribe to MSDN Blogs using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
星期六, 十月 20, 2007
星期五, 十月 19, 2007
星期四, 十月 18, 2007
星期三, 十月 17, 2007
星期二, 十月 16, 2007
星期一, 十月 15, 2007
HOWTO: EWS: Use GetAttachment to download attachments off Mail/Appointment
Hudong 通过 Google 阅读器发送给您的内容:
I have fallen for exchange web services. There are endless possibilities with exchange web services, and product group is still working to make it even better.
Today I have created a neat sample to download attachments off Exchange Server
Sample: DownloadAttachments
Input Params: itemID , folder
public void DownloadAttachments(string itemID,string folder)
{
ExchangeServiceBinding esb = new ExchangeServiceBinding();
esb.AllowAutoRedirect = true;
esb.Credentials = new System.Net.NetworkCredential("USERNAME", "PASSWORD", "DOMAIN");
esb.Url = "http://your-cas-server/ews/exchange.asmx";
//first we need to get the attachment IDs for the item so we will need to make a GetItem call first
//specify the conetent that we want to retrieve
PathToUnindexedFieldType[] ptufta = new PathToUnindexedFieldType[2];
ptufta[0] = new PathToUnindexedFieldType();
ptufta[0].FieldURI = UnindexedFieldURIType.itemAttachments;
ptufta[1] = new PathToUnindexedFieldType();
ptufta[1].FieldURI = UnindexedFieldURIType.itemHasAttachments;
ItemResponseShapeType irst = new ItemResponseShapeType();
irst.BaseShape = DefaultShapeNamesType.IdOnly;
irst.AdditionalProperties = ptufta;
ItemIdType[] biita = new ItemIdType[1];
biita[0] = new ItemIdType();
biita[0].Id = itemID;
//get the items
GetItemType git = new GetItemType();
git.ItemShape = irst;
git.ItemIds = biita;
GetItemResponseType girt = esb.GetItem(git);
if (girt.ResponseMessages.Items[0].ResponseClass != ResponseClassType.Success)
return;
//now that we have the attachment IDs let's request the atthacments and save them to disk
ItemType MsgItem = ((ItemInfoResponseMessageType)girt.ResponseMessages.Items[0]).Items.Items[0];
AttachmentResponseShapeType arst = null;
AttachmentIdType[] aita = null;
if (true == MsgItem.HasAttachments)
{
//create the attachment shape; we want the mime contnet just in case this is an message item so that we can save to disk
arst = new AttachmentResponseShapeType();
arst.IncludeMimeContent = true;
arst.IncludeMimeContentSpecified = true;
//create an array of attachment ids that we want to request
aita = new AttachmentIdType[MsgItem.Attachments.Length];
for (int i = 0; i < MsgItem.Attachments.Length; i++)
{
aita[i] = new AttachmentIdType();
aita[i].Id = MsgItem.Attachments[i].AttachmentId.Id;
}
}
//create a GetAttachment object for the GetAttachment operation
GetAttachmentType gat = new GetAttachmentType();
gat.AttachmentIds = aita;
gat.AttachmentShape = arst;
GetAttachmentResponseType gart = esb.GetAttachment(gat);
//save each attachment to disk
foreach (AttachmentInfoResponseMessageType Attachment in gart.ResponseMessages.Items)
{
switch (Attachment.Attachments[0].GetType().Name)
{
//attachments can be of type FileAttachmentType or ItemAttachmentType
//so we need to figure out which type we have before we manipulate it
case "FileAttachmentType":
//save to disk
FileAttachmentType TheFileAttachment = (FileAttachmentType)Attachment.Attachments[0];
using (Stream FileToDisk = new FileStream(folder + @"\" + Attachment.Attachments[0].Name, FileMode.Create))
{
FileToDisk.Write(TheFileAttachment.Content, 0,
TheFileAttachment.Content.Length);
FileToDisk.Flush();
FileToDisk.Close();
}
break;
case "ItemAttachmentType":
//save to disk
ItemType TheItemAttachment = ((ItemAttachmentType)Attachment.Attachments[0]).Item;
using (Stream FileToDisk = new FileStream(folder + @".\" + Attachment.Attachments[0].Name + ".eml", FileMode.Create))
{
byte[] ContentBytes = System.Convert.FromBase64String(TheItemAttachment.MimeContent.Value);
FileToDisk.Write(ContentBytes, 0,
ContentBytes.Length);
FileToDisk.Flush();
FileToDisk.Close();
}
break;
default:
break;
}
}
}
可从此处完成的操作:
- 在 MSDN Blogs
- 使用 Google 阅读器订阅MSDN Blogs
- 开始使用 Google 阅读器,轻松地与您喜爱的所有网站保持同步更新
Why aren't shortcuts as easy as unix links?
Sent to you by Hudong via Google Reader:
Commenter dingo asks, "Why are shortcuts so hard to manipulate? Why can't they be as easy as unix links?"
Well, if you want something like unix links, then you can just create a hard link. Creating them is about the same difficulty (CreateHardLink
vs link
) and manipulating them is the same since you don't actually manipulate a hard link. You just use it like a regular file (since a regular file is a hard link).
If you want something like unix symbolic links, then you can create an NTFS junction, such as this one that mounts a drive into a directory. (I'm told that Windows Vista expands the repertoire of symbolic links as well.)
But neither of these features is available on FAT (or CD-ROMs or Novell Netware or email), which meant that Windows 95 couldn't use them. Last year I discussed in some detail why shortcuts are files. Maybe that's what your question is really about.
Things you can do from here:
- on MSDN Blogs
- Subscribe to MSDN Blogs using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
星期日, 十月 14, 2007
星期五, 十月 12, 2007
星期四, 十月 11, 2007
星期二, 十月 09, 2007
Anderson lake route
Staring lake route
Home 1 circle at lake
home to lake 0.3587 mile
1.1535 total, lake circle ~0.7948
2 circle = 1.9483
3 circle = 2.7431
4 circle = 3.5379
星期一, 十月 08, 2007
星期五, 十月 05, 2007
星期四, 十月 04, 2007
[Recommended Books] Awesome Debugging Book
Sent to you by Hudong via Google Reader:
I've been exchanging e-mails with Mario Hewardt and Daniel Pravat, authors of the upcoming debugging book "Advanced Windows Debugging".
I must tell you: this post is to share my excitement with this book!
The book covers everything you can imagine regarding native debugging!
Take a look at the table of contents:
Part I – Introduction
1. Introduction to the Tools
Introduces the tools used throughout the book including basic usage
scenarios and download locations. The following tools are covered:
< Diagnosis>Debugging Tools for Windows
UMDH
Microsoft Application Verifier
Global Flags
Process Explorer
Windows DDK
Ethereal
Debug Diagnostics
2. Introduction to the Debuggers
Introduces the fundamentals of the Windows Debuggers including coverage of the different types of debuggers (user mode vs. kernel mode), debugger setup, symbols, crash dumps and much more. The second part of the chapter details the basic and most commonly used debugger commands.
3. Debugger Uncovered
Chapter 3 continues the examination of the debuggers in greater detail. Coverage includes topics such as the inner workings of a debugger (miniature debugger implementation) and a detailed description of the exceptions dispatching mechanism.
4. Managing Symbols and Sources
Without proper symbols debugging is a very hard and sometimes impossible proposition. This chapter covers the important topic of symbol and source management. Topics such as creating private and public symbol packages, setting up a symbol and source server are covered in detail.
Part II – Applied Debugging
5. Memory Corruptions Part I: Stacks
Corrupting the stack is a common programming mistake that can be extremely difficult to debug. Without the proper knowledge of how Windows manages thread stacks as well as the tools available to make debugging stack problems easier developers can spend countless hours navigating a stack corruption. The chapter begins with an overview of Windows stack management followed by a set of scenarios that illustrate common stack problems and how to debug them.
6. Memory Corruptions Part II: Heaps
This chapter continues the study of memory corruptions and focuses on heap related corruptions. The chapter begins with a detailed discussion of the Windows Heap Manager and covers topics such as the front end allocator, back end allocator, look aside lists and free lists. Several scenarios are also included and serve to illustrate some of the most common forms of heap corruptions. A detailed root cause analysis using the debuggers and tools is also included for each scenario.
7. Security
Every so often a developer is faced with an ACCESS DENIED error code without any clues as to why the error was returned. The task of navigating complex security and access denied problems is a covered in this chapter. The primary focus of this chapter is on the Windows native security model and covers the access control constructs available as well as how the debuggers can be used to maximize efficiency when analyzing security problems.
8. Interprocess Communication
Processes typically don't live in isolation rather rely on auxiliary processes to complete processing. This chapter details the intricacies of debugging across processes using RPC. Topics covered include identity tracking (who is calling what), RPC debugger commands and extensions as well as an explanation of a powerful freeware tool called Ethereal that can be used to track interprocess calls that cross machine boundaries.
9. Resource Leaks
Resource leaks are common programming mistakes that can wreak havoc in your application. This chapter studies the most common form of resource leaks (such as memory and handle leaks) and shows how the debuggers and associated tools can be utilized when tracking down resource leaks.
10. Synchronization
A multithreaded environment allows for a great amount of flexibility and efficiency. With this flexibility comes a lot of complexity in the form of thread management. Threads must be made to properly work in tandem without interfering with each other. This chapter introduces the synchronization primitives available in Windows and discusses how the debuggers and tools can be used to debug common thread synchronization problems. Scenarios such as deadlocks, lock contention (lock convoys), indirect deadlocks (such as loader lock) and management of critical sections are discussed in detail.
Part III – Advanced Topics
11. Writing Custom Debugger Extensions
Even though the debuggers include a ton of powerful commands out of the box it is sometimes necessary to extend the core functionality. This can be achieved by writing your own debugger extensions. This provides an in depth discussion of how to develop a custom debugger extension. It will guide you through the overall extensibility mechanism and includes a step by step guide on how to implement a sample debugger extension.
12. 64bit Debugging
With the advent of 64bit architectures, the need to understand how these architectures work and how they can be debugged is critical. This chapter outlines the fundamentals of 64bit debugging. The chapter looks at each topic discussed in the book and details the various differences between 32 and 64 bit debugging. The primary architecture covered is the x64 architecture.
13. Postmortem Debugging
Quite often, it's not feasible to expect to have full access to a failing machine so that a problem can be debugged. Bugs that surface on production machines on customer sites are rarely available for debugging. This chapter outlines the mechanisms available for debugging a problem without access to the physical machine. Topics discussed include the basics of crash dumps, generating crash dumps, analyzing crash dumps, signing up for Windows Error Reporting and using Corporate Error Reporting to maximize postmortem debugging efficiency.
14. Power Tools
This chapter discusses two extremely important tools that can automate much of the debugging process. The DebugDiag is a powerful tool that can help analyze resource leaks, crashes and hangs. It is scripting enabled and allows for a powerful extension model. The second tool discussed is the analyze debugger command which performs a preliminary analysis of the process in question and can automate a lot of the investigative work typically done on a failing process.
15. Windows Vista Fundamentals
Windows Vista introduces a slew of new features and many of those new features come in the form of kernel enhancements. This chapter gives an overview of the most important changes such as the low fragmentation heap, new interprocess communication, new security model and much more.
If it wasn't enough to help you understand my excitement, then read this sample chapter that explains how to debug a heap memory corruption.
By the way, if you wish to apply for our Support Escalation Engineer or Escalation Engineer positions, read this book because it will help you during the interviews. J
I've already ordered mine and I'm looking forward to having it in my hands!
It's going to be released on October 26, 2007.
In this article I comment on other debugging books.
See you on next article.
Things you can do from here:
- on MSDN Blogs
- Subscribe to MSDN Blogs using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
星期三, 十月 03, 2007
.NET Framework Source Code to Ship with Orcas
Sent to you by Hudong via Google Reader:
In what is easily the single best piece of news I have heard since coming to Microsoft, Scott Guthrie has announced today that we will be releasing the source code to the .NET framework when we ship Visual Studio 2008 later this year.
An option will be made available to allow you to step directly into the source from your own code, so you can see exactly what is happening in the .NET framework. This is exactly what developers need, and it will greatly improve the experience of developing on the .NET Framework .
Scott says that the source code and comments to the following will be released:
- BCL libraries (System, System.IO, System.Collections, System.Configuration, System.Threading, System.NET, System.Security, System.Runtime, System.Text, etc)
- Windows Forms
- ASP.NET
- ADO.NET
- XML (System.Xml)
- WPF
The code will be made available on the web, and there will be an option to download it to your machine. Other libraries to be added later include:
- LINQ
- WCF
- Workflow
There is very little I can add to this announcement except to say that it makes me extremely happy. I feel proud to work for a company that offers not only the best tools available, but also open access to the source so that the whole community can fully understand these great frameworks and better debug the tricky parts of their applications.
Here is a link to Scott's post:
Things you can do from here:
- on MSDN Blogs
- Subscribe to MSDN Blogs using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites
星期二, 十月 02, 2007
MultiWall - Wallpaper Tool for Multiple Monitors
Sent to you by Hudong via Google Reader:
Introduction
Everyone enjoys customizing his or her computer to the extent possible, and this almost always includes the desktop wallpaper. Windows XP manages wallpaper resizing pretty transparently, increasing or reducing the image display size, or tiling it as specified. Unfortunately, this isn't quite as smooth if you have more than one monitor. After some tinkering around with display settings and different bitmaps, I threw together a utility to resize images easily so you can customize what shows on each display.
Before reading further, you may want to download the source code in either Visual Basic or C# from the links above the "Introduction" heading. The code is identical in either language, so choose the one with which you're more comfortable. If you haven't yet, download the appropriate version of Visual Studio 2005 Express Edition and let's begin! You might also want to read through earlier articles that I've written about desktop wallpaper (here and here).
Understanding Wallpaper
Most people are familiar with setting wallpaper through the system's Display Properties control panel applet. You browse to an image, select how the image should be sized to fit the screen, and it does its magic. If you have two monitors though, you'll have noticed that it just duplicates the image on each monitor when in Stretch or Center mode, and repeats it unattractively across monitor boundaries in Tile mode. This isn't generally the intent when selecting an image!
Image 1: Windows XP Display Properties - Desktop tab
I just want to be able to select a different image for each screen. In figuring that out though, I learned that the Tile mode can be pretty useful if you happen to have an image of the right size. For example, if you have two displays that are each 1024x768, you can select an image that's 2048x768, select Tile mode, and it will spill across the screens perfectly. This doesn't do much good if your screens are aligned in a non-standard way, at different resolutions, or the image isn't sized right.
With this new understanding in mind, I realized that I could write a utility, that, when given multiple images, could read the display settings and generate a single bitmap with all images sized and positioned properly. Tiling this image results in the perfect fit on each monitor.
Sizing and Placing
Reading your display configuration is as easy as accessing the System.Windows.Forms.Screens collection. Each element is of type Screen and exposes its identifier, resolution, and coordinates. Identifier and resolution should be self-explanatory, but the coordinates may take a little explaining. By default, Windows will place two monitors side-by-side, such that display 1 is to the far-left, and subsequent monitors line up to the right.
The problem comes with unequal resolutions, or monitors of physically different sizes (as mine are). To account for these differences, you can just drag the monitor previews around in the Display Properties dialog until things line up properly. The exact placement is then reflected by the X,Y coordinates for a display. Note that there can be no gap in-between displays, though you could get a pretty crazy configuration by placing two displays almost diagonal to each other. Of course, given your physical monitor layout, this might make sense.
Image 2: Windows XP Display Properties - Settings tab
The first thing the application does is figure out the overall display bounds, taking into account all monitors. In the simple case of two 1024x768 monitors, lined up perfectly side-by-side, the overall bounds would be 2048x768. If you offset them similar to shown above, maybe the bounds become 2048x800. The key is to create a single rectangle that contains all monitors, and to keep track of the visible regions in that rectangle.
To accomplish this, the AddBounds shared/static method (in the BoundsUtilities class) takes an overall Rectangle and a Rectangle to add. The returned Rectangle represents the best fit overall bounds.
Visual Basic
Public Shared Function AddBounds(ByVal sourceBounds As Rectangle, ByVal newBounds As Rectangle) As Rectangle If newBounds.Right > sourceBounds.Right Then sourceBounds.Width += (newBounds.Right - sourceBounds.Width) End If If newBounds.Bottom > sourceBounds.Bottom Then sourceBounds.Height += (newBounds.Bottom - sourceBounds.Height) End If If newBounds.Left < sourceBounds.Left Then sourceBounds.X = newBounds.X End If If newBounds.Top < sourceBounds.Top Then sourceBounds.Y = newBounds.Y End If Return sourceBounds End Function
Visual C#
public static Rectangle AddBounds(Rectangle sourceBounds, Rectangle newBounds) { if (newBounds.Right > sourceBounds.Right) sourceBounds.Width += (newBounds.Right - sourceBounds.Width); if (newBounds.Bottom > sourceBounds.Bottom) sourceBounds.Height += (newBounds.Bottom - sourceBounds.Height); if (newBounds.Left < sourceBounds.Left) { sourceBounds.X = newBounds.X; } if (newBounds.Top < sourceBounds.Top) { sourceBounds.Y = newBounds.Y; } return sourceBounds; }
In the MainForm class, when the application starts up or the display properties change, the UpdateMonitorBounds method cycles through the screens calling AddBounds. It also accounts for the fact that the primary display always establishes 0,0, and screens above or to the left of it will have negative coordinates. This method also creates Bitmap instances for both the preview and the actual desktop display.
Visual Basic
Private Sub UpdateMonitorBounds() screens = Screen.AllScreens overallBounds = New Rectangle() refPoint = New Point() For Each scr As Screen In screens overallBounds = BoundsUtilities.AddBounds(overallBounds, scr.Bounds) Next ' Screens to the left or above the primary screen cause 0,0 to be other ' than the top/left corner of the Bitmap If overallBounds.X < 0 Then refPoint.X = Math.Abs(overallBounds.X) End If If overallBounds.Y < 0 Then refPoint.Y = Math.Abs(overallBounds.Y) End If ' Cancels out the negative values from offset screens Dim correctedBounds As Rectangle = ZeroRectangle(overallBounds, refPoint) previewBitmap = New Bitmap(CInt(correctedBounds.Width / 4), CInt(correctedBounds.Height / 4)) desktopBitmap = New Bitmap(correctedBounds.Width, correctedBounds.Height) End Sub
Visual C#
private void UpdateMonitorBounds() { screens = Screen.AllScreens; overallBounds = new Rectangle(); refPoint = new Point(); foreach (Screen scr in screens) { overallBounds = BoundsUtilities.AddBounds(overallBounds, scr.Bounds); } // Screens to the left or above the primary screen cause 0,0 to be other // than the top/left corner of the Bitmap if (overallBounds.X < 0) refPoint.X = Math.Abs(overallBounds.X); if (overallBounds.Y < 0) refPoint.Y = Math.Abs(overallBounds.Y); // Cancels out the negative values from offset screens Rectangle correctedBounds = ZeroRectangle(overallBounds, refPoint); previewBitmap = new Bitmap(correctedBounds.Width / 4, correctedBounds.Height / 4); desktopBitmap = new Bitmap(correctedBounds.Width, correctedBounds.Height); }
The display preview serves little purpose in its current form, but it could be useful with many monitors. It's a size-reduced version to scale quicker. It also shows the display index (1, 2, etc) similar to in Display Properties. The AddImageToPreview method is a bit long to show here, but it accounts for negative screen values, resizes accordingly, and renders each image onto its corresponding display. The last step draws the number on in two steps using the GraphicsPath object to convert the supplied text to its vector path information. It's drawn in black, a bit smaller in white to create the outlined format. If you only draw with one color, there will always be bitmaps that render it invisible. A white digit with a black outline takes care of this problem.
Visual Basic
Private Sub RenderCaption(ByVal g As Graphics, ByVal bounds As Rectangle, ByVal caption As String) Dim captionFont As New Font(FontFamily.GenericSansSerif, bounds.Height / 4) Dim layoutRect As New Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height) Dim path As New GraphicsPath() path.AddString(caption, captionFont.FontFamily, CInt(captionFont.Style), _ CSng(captionFont.Height), layoutRect, StringFormat.GenericDefault) Dim p As New Pen(Brushes.Black, 5) g.DrawPath(p, path) g.FillPath(Brushes.White, path) End Sub
Visual C#
private void RenderCaption(Graphics g, Rectangle bounds, string caption) { Font captionFont = new Font(FontFamily.GenericSansSerif, bounds.Height/4); Rectangle layoutRect = new Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height); GraphicsPath path = new GraphicsPath(); path.AddString(caption, captionFont.FontFamily, (int)captionFont.Style, (float)captionFont.Height, layoutRect, StringFormat.GenericDefault); Pen p = new Pen(Brushes.Black, 5); g.DrawPath(p, path); g.FillPath(Brushes.White, path); }
The preview appears thus:
Image 3: The MultiWall application preview window (photos by the author)
Rendering the actual desktop image is almost the same, though at full-size and without the digit overlay. One complication is that monitors can be in the "negative" zone (to the left or above the primary display). The composite bitmap must have its 0,0 corresponding to the 0,0 of the primary display. To account for the negative images, you must actually render the images to the far right, or far bottom. The tiling effect performs a "wrap-around" to make it fit. The worst part, is that, depending on where it is, you must draw the image multiple times to get all directions to tile properly!
Dragging, dropping, and layout
Figuring out a good way to actually set the monitor's wallpapers posed a design challenge. I originally had Browse buttons in the preview window, but it was unwieldy. I really wanted to be able to drag-and-drop onto the preview regions, but figuring out the drop coordinates relative to the original images, accounting for negative coordinates and a user-resizeable window wasn't realistic for the purposes of this article, but it's definitely possible! Perhaps the easiest way would be convert the single PictureBox to dynamically placed PictureBox controls for each display. But I digress...
My solution was to create a drop region in the top-middle of each display. If you drag an image file to this region it will update the wallpaper accordingly. Images are always cached using a WeakReference to avoid reloading if you switch back and forth. Currently used images are also stored in a collection to provide a hard reference to prevent garbage collection on those. If an image is reclaimed from cache it just gets reloaded.
Image 4: The bitmap drop region
These windows are set partially transparent and will disappear when the preview window is minimized to tray, unless the Show Drop Regions option is checked in the tray menu. This setting is remembered when the application is closed.
Each time an image is dropped onto a region, the code builds both the preview bitmap and the desktop bitmap. The application remembers the filenames so upon next startup it can show the individual bitmaps. It could load the desktop's composite image, but it would need to follow extra steps to chop the composite image back into its constituent parts to redraw when one monitor is updated.
For more information on the registry update and system call required to actually update the wallpaper at the system level, see my earlier articles (referenced in the introduction). The generated composite Bitmap file is saved to the My Pictures folder with the name "MultiWallImage.bmp". The file could be hidden as an extra step as well. Notice that it's quite large (12MB on my system!). Unfortunately, Windows XP requires a BMP file. Though you can supply a JPEG or other format using the Display Properties dialog, it converts it to BMP before it shows it.
Next Steps
No program is ever complete! I wanted to add a way to take a single large image and have it chopped up in the best way to span multiple monitors, but it seemed more complex than expected when I dug into it. I also wanted to add drag-and-drop to the preview window. The preview window doesn't really serve much purpose, but it was a good exercise. The program could be made more efficient with a background thread, and it should only redraw images if display settings change. Currently if you drag an image to display #3, all display's images are redrawn/rescaled. Finally, an image randomizer would be easy to add. Use Windows (Desktop) Search or a given folder and cycle wallpapers upon startup/interval/random.
Conclusion
This article covered some graphics drawing techniques, drag-and-drop, system events, and wallpaper settings. It's not the first wallpaper application on Coding 4 Fun, but it's probably the best (of mine anyway!). For any comments, questions, or suggestions, contact me through my blog. Happy papering!
Arian Kulp is an independent software developer and writer working in the Midwest. He has been coding since the fifth grade on various platforms, and also enjoys photography, nature, and spending time with his family. Arian can be reached through his web site at http://www.ariankulp.com. |
Things you can do from here:
- on MSDN Blogs
- Subscribe to MSDN Blogs using Google Reader
- Get started using Google Reader to easily keep up with all your favorite sites