Thursday, February 4, 2010

Drag and drop in Visual Studio 2010

 

Let me explain first how drag and drop works in a WPF application:

1) the Win32 window hosting the WPF controls needs to be registered as a drop target with Windows by calling RegisterDragDrop. When some object is dragged, Windows selects the “closest” Win32 window registered for drag drop under the mouse, and then it calls functions like DragEnter/Drop/etc on the IDropTarget interface provided at registration. WPF does this registration for HwndSource windows, and when an object is dragged over a WPF window, WPF will be called.

2) the WPF control that wants to intercept the drop needs to specify UIElement.AllowDrop=true. When called by Windows, WPF will select the innermost WPF control under the mouse that allows drop and will route to it WPF-style drag and drop events (e.g. PreviewDragEnter events will be tunneled to that control, then DragEnter events will bubble up). The controls and its parents have a chance of intercepting these events.

3) the control or one of the parents needs to recognize one of the formats of the data being dragged, and allow the drop. If no control recognizes the format, the DropEffect will be None and the drop will not be possible.

Now back to Visual Studio.

Visual Studio 2010 and later are WPF applications. The main window and floating windows (toolwindows or documents) are HwndSource, thus are registered for drag and drop by WPF. The shell sets AllowDrop=true on the root WPF elements in these windows, and since this is an inherited property, all child controls (e.g. the toolwindows contents) will automatically allow drop as well.

If the toolwindows host WPF content but they don’t intercept the drag & drop events, the shell will eventually intercept the bubbling WPF events, and will attempt to extract from the dropped data file names to be opened either as solutions/project or in editor windows. Similarly, if the toolwindows host Win32 elements but don’t register them as droptargets with Windows, Windows will pick the shell’s main window as drop target and again the shell will check the dropped data if it contains filenames that can be opened in editor.

A) Drag and drop over Shell-owned elements

The shell owns some elements in the Visual Studio UI, e.g. the frames of the toolwindows and document windows, document tabs in the document well, the main window’s background area, main window’s toolbars, toolbars in toolwindows hosted by the shell, etc., thus it controls dragging and dropping over these elements.

The shell understands only the DataFormat.FileDrop (CF_HDROP) format. This format is used for instance when one or more files are dragged from Windows Explorer. When dropped over Visual Studio’s main window, VS will use the dropped file names to open the files in a Visual Studio editor.

This works when dropping over most shell elements, with a couple of exceptions:
- dropping over tabbed toolwindows tabs or document tabs is disallowed: instead this is used to switch the active toolwindow or document in the tab group.
- dropping over comboboxes in toolbars (if editable, these allow drop with Text format)
- dropping over the main window’s title is not possible (this is a WPF issue)


B) Drag and drop over toolwindows’ content

A tool window implementer has the option of using Win32-based content or using a WPF element as content. When using the VsSDK/MPF classes like ToolWindowPane, the content can be exposed using either the Window or Content properties from the base class.

Win32 content

Whenever a Win32 window is returned from ToolWindowPane.Window, from IVsWindowPane.CreatePaneWindow, or indirectly from IVsUIElementPane.CreateUIElementPane via IVsUIWin32Element, that toolwindow will have a Win32 content. To intercept drop operations on the toolwindow content, the toolwindow’s implementer will need to register the Win32 window with Windows by calling RegisterDragDrop, and providing an IDropTarget, then handling the Windows-style drag and drop calls.

An example of such toolwindow is SolutionExplorer, which registers its content to allow D&D of solution and project items between the projects in the tree.

WPF content

Whenever a FrameworkElement is returned from the ToolWindowPane.Content property, from IVsUIElementPane.CreateUIElementPane (or indirectly via IVsUIWpfElement), the shell will host that toolwindow’s content in a pure-WPF hierarchy, without intervening HWnd. WPF-style events will then flow freely up/down the visual tree starting with the main window (or the floating window root, when the toolwindow is floating).  Conditions 1) and 2) are automatically satisfied, and all you need to do is satisfy 3) – intercept the WPF events for the dropped format you understand. Again, if the toolwindow does not intercept the dropped data and mark the WPF events handled, the shell will intercepts  them and will either deny the drop or will open the files in editors (if the data is in the FileDrop format accepted by the shell).

See the sample below for an example.

C) Drag and drop over toolwindows’ toolbars

To use a shell-implemented toolbars (WPF), a toolwindow can host it in two modes:

a) Letting the shell to host the toolbar. E.g. get an IVsToolWindowToolbarHost from the window frame by calling IVsWindowFrame.GetProperty for VSFPROPID_ToolbarHost, call AddToolbar on the toolbar host. The shell will host the toolbar directly in a WPF tree without intervening hwnds. Any drops over the toolbar will be handled by the shell. To intercept drops over the toolbar area, the toolbar has to be added using a different function: instead of using IVsToolWindowToobar.AddToobar, query the IVsToolWindowToolbarHost2 interface from the toolbar host and call AddToolbar2 method. This allows providing an object implementing IDropTarget interface that will be called by the shell when the drop happens over the toolbar area.

b) Hosting the toolbar yourself. E.g. If your toolwindow content is Win32-based, create a Win32 window child of the toolwindow’s content, and an object implementing IVsToolWindowToolbarHost interface, call  IVsUIShell.SetupToolbar to associate the Win32 child with your toolbar host, then call IVsToolWindowToobar.AddToobar to add the toolbar into the host. This way you can place a toolbar anywhere in your toolwindow’s area. If the toolwindow’s content  is already registered as drop target by calling RegisterDragDrop, Windows will select it as the “closest” drop target under mouse when the drop happens under the toolbar area, too, and you’ll receive the Windows-style calls on the drop target interface. You can also register the toolbar host child window as a separate drop target if you so wish.

------------------------------------------------------------------------------------------------------------------------------

The following sample demonstrates drag and drag of a custom data format, and intercepting the drop in a WPF control. It also demonstrate dragging of data in formats understood by editors and VS shell.

http://www.alinconstantin.net/Download/Example.SimpleDragDropInVS.zip

You need VS2010 and VSSDK2010 installed in order to build the sample and run it under the experimental hive. To view the toolwindow, use the View/OtherWindow/DragAndDropToolwindow command, then drag the labels over the indicated areas.

Capture

Friday, October 23, 2009

A MSSCCI Primer (How Microsoft Source Code Control API works)

I’ve intended to publish this article long time ago, and never found the time to finish all I wanted to wanted to be in it. I’ll publish it now as is, hoping it may still help someone get started…

------------------------

I've been recently asked what's the correct order in which MSSCCI functions should be called for integrating an IDE application like Visual Studio with a MSSCCI (Microsoft Source Code Control) provider.

While looking for references, I realized that the MSSCCI documentation in MSDN is a good reference for the API functions, but it doesn’t do a good job in describing MSSCCI concepts and how to start implementing a MSSCCI-compliant source control provider. It looks like it's time to write such page...

What is a MSSCCI dll?

Basically, a MSSCCI source control provider is a 32-bit Native dynamic link library, exporting a couple of predefined functions with names beginning with “Scc” (e.g. SccAdd, SccCheckout, etc). A MSSCCI provider doesn't need to implement all these functions, but there is a subset of the functions that must be implemented by any provider (more on that later) to make the provider be usable by an Integrated Development Environment (IDE) like Visual Studio.

An IDE loads the MSSCCI dll by calling LoadLibrary or LoadLibraryEx. After that it usually looks up and binds the MSSCCI function by name by calling GetProcAddress, and will start calling the Scc functions directly. When the IDE is done using the MSSCCI provider it can unload the dll by calling FreeLibrary.

There are no Unicode versions of the functions, therefore Unicode-ANSI conversion may need to be performed as necessary by both IDE and the source control provider.

Because the MSSCCI providers are 32 bit dlls, they cannot be loaded directly in 64 bit processes. To the best of my knowledge, there are no plans of creating a 64-bit version of the interface for loading a MSSCCI provider in a 64-bit process. However this limitation can be circumvented by creating a 32-bit COM object that loads and wraps the MSSCCI dll, further exposing COM interfaces functions similar to MSSCCI functions; the COM wrapper object can be co-created in 64-bit processes.

MSSCCI Connections

To perform source control operations with a MSSCCI provider, an IDE needs to open a connection; this is done with the SccOpenProject function. A connection is simply an association (1:1 mapping) between a folder in the source control storage database (project name in MSSCCI terms) and a folder on local disk (local project path). An example (for SourceSafe) might be:

        C:\My Solutions\Wincheat <----> "$/Solutions/Wincheat", CDFAAAA

When the connection is open, the provider can also perform authentication of the user for accessing the source control storage, etc.

Note there are no restriction on the folders mapping. Multiple connections/mappings can be opened from the same local folder pointing to different folders in the scc database; multiple connections can be opened from various local folders pointing to the same project in the scc database; and mapped projects can overlap.

After opening a source control connection, further source control operations are possible using that connection.Within a connection, files are identified only based on their local path; the path must be under the cone defined by the connection local root. The path in storage is automatically deduced based on the connection root folders. Files outside this connection root should not be controllable through this connection.

E.g. The C:\My Solutions\Wincheat\WinCheat.sln can be controlled through the connection above and is associated with $/Solutions/Wincheat/Wincheat.sln. The file C:\My Solutions\OtherSolution\OtherSolution.sln can’t be controlled using this connection, even though in the scc database there may be an matching item at $/Solutions/OtherSolution/OtherSolution.sln.

In the following example, there are 3 connections open

C:\My Solutions\Solution1             <----> "$/Solution1", BCDAAAA
D:\Project1                           <----> "$/Solution1/Project1", KRFAAAA
C:\My Solutions\Solution1\SubProject  <----> "$/Solution1/Project1", KRFAAAA

Depending on which connection is used, the same file in storage $/Solution1/Project1/File.txt can be referenced either as C:\My Solutions\Solution1\Project1\File.txt, D:\Project1\File.txt or C:\My Solutions\Solution1\SubProject\File.txt

A MSSCCI provider implementer should not make assumptions (based on enlistment or other similar mapping information specific to that provider) that a file in the storage is associated with only one file on local disk - at any time a new MSSCCI connection can be opened from any folder on local disk and the same file in storage can be accessed using that connection.

When a connection is no longer needed, the IDE should close it using the SccCloseProject function.

The server path used for opening a connection is specific to each source control provider. An IDE application has no idea of the format (and should not make any assumptions on the format). You may be asking yourself where does the projName string used in SccOpenProject comes from. Usually, during an Open from source control operation the IDE will call SccGetProjPath which allows the user to select a folder in the source control database. The string identifying the selected project is returned to the IDE, and used immediately in new connections, or is persisted in solution/project files and used on subsequent open from disk of that project/solution. Also, the IDE may attempt to retrieve server path strings from mssccprj.scc file if the source control provider creates and maintains such files.

A typical fragment showing opening a connection could look like this:

SccOpenProject(context1, project1, localpath1) open in context1 a connection
project1<---->localpath1
SccCheckin/SccGet/etc invoke source control functions using the connection open by using file paths under localpath1
SccCloseProject(context1) close the connection open in context1

 MSSCCI Contexts

You may have noticed that most of the MSSCCI functions have an argument LPVOID pvContext.

A context is obtained by calling SccInitialize and can be disposed of by calling SccUninitialize.

A context allows identifying the connection that should be used with a specific operation like Get, Checkin, etc, because at one point in time, at most one connection can be opened within a context.

A context is simply a data structure specific to each source control provider; it usually contains information like flags specifying whether a connection is opened or not within that context, information about the connection open, etc.

The typical order of operations with a source control database is:

SccInitialize() receives context
SccOpenProject(context, project, localpath) open in this context a connection
project<---->localpath
SccCheckin(context)/SccGet(context)/etc perform any source control operations using the context and the project<---->localpath connection. The file paths needs to be
SccCloseProject(context) close the connection open in this context
SccUninitialize(context) dispose of context

If an IDE needs to open a different connection to the database:

a) it can reuse an existing context for the new connection, but first it will have to close the currently open connection within that context. Typical order of operations is:

SccInitialize() receives context1
SccOpenProject(context1, project1, localpath1) open in context1 connection
project1<---->localpath1
SccCloseProject(context1) close the connection open in context1
SccOpenProject(context1, project2, localpath2) open in context1 new connection
project2<---->localpath2
SccCloseProject(context1) close the new connection open in context1
SccUninitialize(context1) dispose of context1

b) it can create a new context and open the new connection with that context. For this to work, a provider must support the SCC_CAP_REENTRANT capability to declare it is reentrant, thread-safe and that it supports opening multiple connections. An order of operations may be:

SccInitialize() receives context1
SccOpenProject(context1, project1, localpath1) open in context1 connection
project1<---->localpath1
SccInitialize() receives context2
SccOpenProject(context2, project2, localpath2) open in context1 new connection
project2<---->localpath2
SccCloseProject(context1) close the new connection open in context1
SccCloseProject(context2) close the new connection open in context2
SccUninitialize(context2) dispose of context2
SccUninitialize(context1) dispose of context1

Note that operations on multiple contexts can be interspersed any way you like as long as the order of the operation within a context is the correct one.

Versions, capabilities and extended capabilities

When calling into a MSSCCI provider, an IDE needs to know which source control functionality is supported by the MSSCCI provider (which functions are implemented). There are a couple of functions that return this information.

SccGetVersion is one of the first functions an IDE will call. This returns the version of the MSSCCI provider (currently there can be providers implementing versions 1.0, 1.1, 1.2 or 1.3 of the MSSCCI spec). Certain functions are defined only by higher number versions MSSCCI spec (were introduced later). Thus if a provider reports supporting version 1.1 of the spec, an IDE won’t even bother binding and calling a function like SccWillCreateSccFile introduced in version 1.2 of the spec.

When a MSSCCI provider declares implementing a specific version of a spec, it is not required to implement all the functions defined by that spec version. For instance, a MSSCCI 1.2 provider may implement SccCreateSubProject, but may not support features like batching (SccBeginBatch) or viewing file history (SccHistory).  An IDE will not call a function if the MSSCCI provider does not declare supporting it.

To define the functionality supported, a provider should return the lpSccCaps capabilities flags during the call to SccInitialize(). E.g. Set and return the bit SCC_CAP_HISTORY in the lpSccCaps if your provider supports history operations.

For MSSCCI 1.3 and later providers, additional capabilities flags can be returned by implementing the SccGetExtendedCapabilities() function.

Beside flags specifying which functions are implemented, capabilities flags may specify other information about the provider, e.g. whether comments are supported on certain operations.

Note that an IDE may only use providers implementing specific functionality. E.g. VisualStudio 2002 and later can only use source control providers supporting multiple connections (reentrant providers, with version 1.1 or greater and defining SCC_CAP_REENTRANT flag).

If the provider does not define a capability flag introduced by a later MSSCCI spec version than the version implemented by the provider, the IDE assumes that functionality is not available in the provider, and may fallback to other scc operations. E.g. If a MSSCCI 1.1 provider is used with VS2003 and later, the lack of the SCC_CAP_MULTICHECKOUT capability will make VS attempt other ways of determining whether the provider supports or not multiple checkouts. Or, if a MSSCCI 1.2 provider is used with VS2005 and later to control websites, recursive enumeration of files in the source control database using SccPopulateDirList is not possible and VS will try alternative (and slower) ways of achieving the same result, using SccPopulateList and recursive SccGet operations.

Windows 7 cannot access Smb shares on Infrant ReadyNAS

 

Yesterday I installed Windows 7 upgrading from Vista, which preserved all my settings. Almost. After the first login, Windows 7 popped up balloon warnings that “Could not reconnect all network drives”

NetworkDrives

It turned out that all the drives I had mapped to Samba shares on the Infrant ReadyNAS system and that were working fine in Vista were now inaccessible, and they were showing as disconnected in Windows Explorer.

NetworkDrives2

Double clicking the shares in Windows Explorer, or attempting to access the server by address \\alinc-nas was displaying a logon prompt. Typing the correct password and pressing OK was useless, the logon dialog came back with a “Logon failure: unknown user name or bad password” error.

Logon2 

Attempting to view the shares from command line with “net view” was no better, this one complained “System error 53 has occurred / The network path was not found” or “System error 5 has occurred / Access is denied”

Command

I searched the net and eventually I found the solution. Thanks to Brandon for his article!

The problem can be solved by modifying a security policy, as described below:

- Open the StartMenu and search for “Local Security Policy”. Right click the application icon and choose to RunAsAdministrator. (alternatively you can open the Run dialog and launch “secpol.msc”).

- In the “Local Security Policy” window, expand SecuritySetting/LocalPolicies/SecurityOptions folders in the left pane tree and locate “Network security: LAN Manager authentication level” in the right pane list.

- Double click the line and change its value from the default “Send NTLMv2 response only” into “Send LM & NTLM – use NTLMv2 session security if negotiated”. Click Ok and agree with the warning. You’re done! The shares should now be accessible (there is no need to reboot).

image

image

Wednesday, November 5, 2008

How to migrate from SourceSafe 6.0 to VSS 2005

 

I’ve seen this question asked a couple of times, so I thought it might be time to write a blog entry to have people to point to when I’ll see it again…

Let me start by saying there are no database format changes between VSS6.0 and VSS2005, thus there is no need to convert the database (like it was the case with previous versions). VSS 6.0 can use a database created with VSS 2005, and vice versa (and only VSS2005 will benefit from new features like checkout local version, time zones, etc).

There are two possible migration paths:

a) Want to upgrade from VSS 6.0 to VSS 2005 on the same machine

Since there is no database conversion required, all you need to do is to install VSS 2005. You may install VSS6 and VSS2005 side by side if you want to test the new bits, but should you decide to uninstall VSS6 you will need to repair your VSS2005 installation (or reinstall it).

I recommend uninstalling first VSS 6.0. The uninstall will not delete existing VSS databases on the machine. After that, simply install VSS 2005. If you do it in this order, all the VSS binaries (ssapi.dll, ssscc.dll) will remain registered correctly, and you should be able to just open VSS2005 and have things working as before.

b) Have a machine with VSS 6.0 but want to setup a  new server with VSS2005

Start by setting up the new server machine (install OS, etc.), install IIS if you need to use the database with FrontPage or plan to use VSS remote.

Install VSS2005 on the new machine. VSS2005 does not create a new database on setup, like it was the case with VSS6.0.

A VSS database is comprised by a couple of files on a network share. You will have to copy the VSS databases from the existing machine onto the new machine. Identify the VSS database folders on the old machine. Make sure there are no users still accessing the old database (a good way to do this is to disconnect/remove the network shares on the old machine). Copy the database folder into a new folder on the new machine. Any recursive copy command can be used (xcopy /s, robocopy /mir, WindowsExplorer, etc). On the new machine, share the database folder.

If you’ve been using the VSS database with FrontPage Server Extensions, you’ll need to write a registry key on the new machine. The VSS2005 installer can’t write this key for you like VSS6 did, because it does not create a new database during setup.

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SourceSafe]

“API Current Database”=”Path to the database on the new machine”

Have all other VSS database users uninstall their VSS 6.0 and install VSS2005. While the database can be used in a mixed client environment, it’s recommended that all clients use VSS2005 to benefit of the new features and avoid inconveniences (e.g. VSS6 users won’t be able to merge UTF8 or Unicode files checked in with VSS2005).

Communicate the new database path to all all other team members and have them open the new VSS database by pointing VSS Explorer to the new database.

You may also want now to consider using the new features of VSS 2005. E.g In SSAdmin, Tools/Options/General page consider whether you want to enable CheckoutLocalVersion, set a time zone for the database in the TimeZones tab, use Server/Configure dialog and decide whether you will use this database for remote access or want to configure the LAN service for better performance on LAN, etc.

Sunday, June 29, 2008

Cannot see shared folders or mapped drives on XBox 360's Media Center Extender that are visible on the Vista Media Center PC

On my Vista PC named Jupiter and running Media Center, I logon as Alin and I am able to see shares from another computers (e.g. from a Linux box that is my NAS device). Some of these drives are mapped to local drives on my account, e.g. M:\ -> \\nas\media\music

I setup my Xbox 360 as a Media Center Extender, however when I go to the Library setup and I try to add a new folder to the library, I am no able to select the shares from my NAS device: in the local drives I only see the C:\ drive, and in the folders shared by other computers I don't see the shares from the Linux box...

Media Center Extender uses a local username named something like MCX1 on the MC PC. It is for this MCX1 user that you have to map a drive to the shared folder to make it appear in the Library as a local drive... This can be done with a NetLogon script.

Start by creating a folder %Windir%\System32\Repl\Import\Scripts. Now create a batch file, where you map the drives.  An example might look like this:

    @echo off
set CREDENTIALS=/user:LinuxBox\[Username] [Password]
net use P: "\\LinuxBox\media\Pictures" %CREDENTIALS%
net use M: "\\LinuxBox\media\Music" %CREDENTIALS%


Save this file in the folder you created earlier, e.g. as MCXLogonScript.cmd. The location is important. I've read articles this logon file should be placed in C:\netlogon; the help mentions it should be saved in \\vistapc\netlogon share, etc., but none of those worked for me. I found the correct path where Windows was looking for the file with ProcessMonitor, and that path on my Vista box was %Windir%\System32\Repl\Import\Scripts.



It's time to associate the logon script with the MCX1 user.  Go to Control Panel -> Administrative Tools -> Computer Management. Under SystemTools/LocalUsersAndGroups/Users, select the MCX1 user and display its Properties. In the Profile tab, type just the file name, MCXLogonScript.cmd.



mcxlogonscript



Go to the XBox 360. Close and reopen Media Center here - it will logout and re-login on the PC with the MCX1 user, and this time it will read the logon script and map the drives. If you go now to Tasks/Setting/LibrarySetup and choose AddFoldersToWatch and select AddFoldersOnThisComputer, now you should see the M:\ and P:\ drives that were mapped by the logon script beside the C:\ drive.

Windows Media Center not recognizing and not displaying jpg images - showing "unable to display picture" error

Last week I tried to view on my TV a couple of pictures recently snapped using an XBox 360 as a Media Center Extender connected to my Vista PC. As much as I tried, I could not convince the Media Center to display the pictures - it was simply not recognizing them. Here are the symptoms I was experiencing:

1) adding the folder containing the pictures to the Media Center Library (using WMC interface) was recognizing the number of files, but when to display the pictures in that folder, it was showing "0 pictures". I tried with folders placed in different locations (my account's Pictures folder, the Public Pictures folder, a network folder on my NAS box, etc) without any success.

2) adding the folder containing the pictures using Media Player's Library worked halfway. When the pictures were added from a NAS folder the pictures were added to the library, but Media Player was not able to show their mediathumbnails (for some reason, it was showing correctly the CR2 files, but not the JPG files).  Photo cameras write the images on memory cards,which are usually formatted as FAT, and the names are capitalized, like IMG_0001.JPG. I was copying the photos on my Infrant ReadyNAS 600 device which uses Linux/ext2 as the file system, which is case sensitive. When MediaPlayer was adding the images to its library, he was changing the case of the extension, and was adding the files as IMG_0001.jpg (This could be seen by looking at the Properties of the file in the library). Because the files were hosted on a case-sensitive Samba share on my NAS/Linux box, trying to view the file was displaying "File not found" errors. It believe this is a bug in MediaPlayer, so I reported it to Microsoft. Meanwhile, I looked at Infrant/Netgear ReadyNAS add-ons and I found ToggleCaseSensitivity that I used to switch the file system to be case-insensitive. After this, MediaPlayer showed correctly all the files in its library.

3) now back to MediaCenter. WMC reuses the MediaPlayer's library, thus it should have displayed the files I was able to see with MediaPlayer. However, that turned out not to work as expected. I tried to browse the library ByFolder, and I was navigating to the folders with pictures, but they only displayed "0 items". Trying to enter the folder showed "No pictures were found" message. I also tried to browse the library ByDate, navigate to the year and month when the pictures were taken. This had a bit more success in the sense that at least it displayed the file names. However, only placeholders were shown for all pictures, with just the picture names. Clicking on one of the files to show the picture caused Media Center to show a message "Unable to display the picture".wmc2wmc1

I searched the net and found that many other users had similar problems; there were references to the jpg file associations being messed up.

Indeed, in the registry the file associations for the jpg extension was looking like this:

   [HKEY_CLASSES_ROOT\.JPG]
@="JPG_auto_file"
"Content Type"="image/jpeg"


Comparing with the setting of another Vista machine, it turned out the important part missing that was causing MediaCenter to skip the files was a missing PerceivedType registry value, that should have been set to image. (The ContentType was also missing - I restored a couple of weeks ago, when I discovered without it Windows Live Writer has troubles with images - see previous posts). I was also missing the PersistentHandler setting; the  JPG_auto_file was written by IrfanView, which was associated with the jpg files. I don't know if IrfanView was responsible or not for the missing values...



Anyway, by default, the registry values should look like this:



   [HKEY_CLASSES_ROOT\.jpg]
@="jpegfile"
"Content Type"="image/jpeg"
"PerceivedType"="image"


wmc3I was missing similar keys for the  *.jpeg file association.



So I manually added the PerceivedType setting in registry and I've restarted MediaCenter; it immediately recognized the jpg pictures, and now everything looks good again!



If you want to restore the jpg/jpeg file associations to their default values, you can edit manually the registry or you can save the setting below to a file with *.reg extension, then double click the file in Explorer.



 





----------------------------------------
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.jpg]
@="jpegfile"
"Content Type"="image/jpeg"
"PerceivedType"="image"

[HKEY_CLASSES_ROOT\.jpg\OpenWithProgids]
"jpegfile"=""
"WindowsLive.PhotoGallery.jpg.12.0"=""

[HKEY_CLASSES_ROOT\.jpg\PersistentHandler]
@="{098f2470-bae0-11cd-b579-08002b30bfeb}"

[HKEY_CLASSES_ROOT\.jpeg]
@="jpegfile"
"Content Type"="image/jpeg"
"PerceivedType"="image"

[HKEY_CLASSES_ROOT\.jpeg\OpenWithProgids]
"jpegfile"=""
"WindowsLive.PhotoGallery.jpg.12.0"=""

[HKEY_CLASSES_ROOT\.jpeg\PersistentHandler]
@="{098f2470-bae0-11cd-b579-08002b30bfeb}"
----------------------------------------

Saturday, June 21, 2008

Speeding up Windows Vista boot and shutdown times

 

One of my friends installed today Vista and complained the boot was taking almost 2 minutes, much longer than in XP. I became curious and I thought I should check on my system what are the boot times...

I have Vista installed fore a year and a half now, and I don't boot my computer very often. It turned out that for my system, the boot time took more than 4 minutes!!! 1 minute until the login screen, 4 minutes until the system was idle - this was on a Intel DualCore 6600 (2.4GHz) with 2 GB RAM, the machine I bought in December 2006.

It turns out Microsoft has released some great tools, XBootMgr and Performance Analyzer, that can help you improving the performance of the boot and shutdown times. They are included in  Windows Performance Tools Kit. For help with running the tool, see the On/Off Transition Performance Analyzer page. I downloaded the kit and installed it in C:\Program Files\Microsoft Windows Performance Toolkit.

You should also download the autologon.exe tool. It allows you specifying a username and password that will be used for automatic logon during the performance measuring process. I downloaded the zip file and extracted the tool. From an elevated command prompt, I run the tool like "autologon /username:Constantin\Alin /set" and typed my password. (To open an elevated command prompt, open StartMenu, write "command" in the search box, right click the "Command Prompt" and select "Run as Administrator")

I did a first run with "xbootmgr.exe -trace boot" (the computer will restart automatically in 5 seconds after running the command). As I told you before, the first boot took more than 4 minutes. After reboot I run  "Performance Analyzer" from the icon installed in StartMenu (or run xperfview), and use the Trace/Open menu item to open the *.etl (event trace log) file saved in the same folder. At a first look it's pretty confusing understanding the log graphs, but the first thing that was clear was that disk accesses were slowing things down. The CPU was used 20% average, but the disk was hit really hard, close to 100% all the time.

Here are some simple things that you can try to reduce the disk access times:

1) Defragment the harddrive. The defragmenter in Vista can be invoked from StartMenu (search for "defrag"). Click the "Defragment Now" button in the dialog and select the drives to defragment. The UI sucks, as there is no progress indicator. You can also invoke the tool from command line ("defrag C: -a -w" if you want to perform a full defragmentation), but again there is no progress indicator. Expect to wait a couple of hours to complete...

2) Eliminate unneeded services and startup programs. Nowadays almost every program you install thinks it's necessary to add either a service or a program to run at computer startup, without you actually needing that functionality, or adding features that can be accessed other ways.

The tools to use for eliminating unneeded services and startup programs are the ServiceManager (accessible from StartMenu, search for "Services"), and either Autoruns, Windows Defender (in Tools/SoftwareExplorer/Startup Programs), or if you're familiar with the registry use directly RegEdit.exe and look under the following keys: HKLM\Software\Microsoft\Windows\CurrentVersion\Run and HKCU\Software\Microsoft\Windows\CurrentVersion\Run.

For services, look at the services that are Started and decide whether you need them. Look especially for 3rd party services. If you're not sure what a service does, search its name or the program name on Google, or on sites like BleepingComputer, and you'll find information describing them. If you don't need these services, set them to Disabled or Manual.

For applications, I prefer leaving the keys in registry in case I need them at a later time, but prefix the application paths with something like "donotrunthisapp" that will cause Windows to skip running the application because it won't find a donotrunthisapp.exe executable.

a) Services used by hardware I don't have. If you don't have on your computer devices using Bluetooth, SmartCard, WiFi, TabletPCPen, there is no reason why you'd keep these services enabled...

b) Helper programs. There are a lot of these, and I haven't found any downsides by stopping them.

c) Update checkers. A lot of applications install either services or startup programs that checks whether they are any updates available for them. I don't understand why these programs needs check for updates on every boot instead of scheduling a task or even better when they are used to run once every week.

d) Speed launchers and cache managers. Yes, they may speed up their application, but when their number is growing, they reduce the overall performance of the system...

Here is a list of what applications I disabled on my machine (I was amazed myself how big the list was):

Services:  PnkBstrA (PunkBuster Service Component installed by BattleField game and not removed when the game was uninstalled), GoogleUpdater (installed by GoogleEarth), NVIDIA Display Driver Service (some helper service), Adobe LM (set to Manual instead of Disabled, this is the license manager for Adobe software and will be started when needed), NMIndexingService (Nero media indexing service), Creative ALchemy AL1 Licensing Service (I set to Manual), Cyberlink RichVideo Service (RichVideo - I don't need enhanced video editing support), Bluetooth Support Service, Tablet PC Input Service, Smart Card, Smart Card Removal Policy, TPM Base Services (I set to AutomaticDelayed), etc.

Startup programs: CTHelper and CTxHlp (Creative help programs and API extensions), NMIndexStoreSvr (more Nero indexing), NBKeyScan (used by NeroBackItUp), Steam (used by HalfLife games), RemoteControl, LanguageShortcut and BDRegion (used by Cyberlink DVD software), Adobe Reader Speed Launcher, ehTray (used by MediaCenter tray application), other update software like QuickTime Task, SunJavaUpdateSched, TkBellExe (for RealPlayer),  NvCplDaemon (not needed, I don't overclock the graphic card), NvMediaCenter (not needed to run in tray, display settings can be changed in control panel), etc.

This is where the biggest improvement came from. After this step, the boot took only 2:10 minutes (30 seconds till the logon screen, 30 more seconds until the desktop appeared, 2:10 until idle)

3) Finally, run again the performance tool to force existing internal operating system optimization mechanisms to update their state based on the current configuration of the system.

To do this, I run the "xbootmgr.exe -trace boot -prepSystem". For me it rebooted the computer twice. On the first reboot, it decreased the boot time to 1:55 minutes (30 sec until login, 45 until desktop was shown, 1:55 until idle). It then took about 15 minutes to optimize the boot performance, and rebooted again. This time, the whole boot process took 1:08 !!! (26 seconds till login, 1:08 until idle).

In the end, don't forget to disable the automatic logon. From an elevated command prompt, run the tool like "autologon /delete"

 

In conclusion, out of 21 applications I was running on startup, I kept only 6 of them I needed; I also removed 10 unneeded services; defragmented the harddrive and optimized the booting time. With all these changes, I was able to reduce the Vista boot time on my computer from more than 4 minutes to only 1 minute and 10 seconds (with the desktop usable in less than 45 seconds)!