Tonight I ran into a problem trying to uninstall a Windows Service via a batch file. The batch file is simple:
C:\Program Files\MyProduct\uninstsvc.cmd@echo off
:: get the Framework directory
set NETFX=%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727
:: stop the service
net stop MyService
:: uninstall the service
%NETFX%\installutil /u MyService.exe
Since MyService.exe is in the same directory as the batch file, this works as long as my working directory is C:\Program Files\MyProduct. However, if I call the batch file from any other working directory, I get this output:Uninstalling MyService service...
Microsoft (R) .NET Framework Installation utility Version 2.0.50727.312
Copyright (c) Microsoft Corporation. All rights reserved.
Exception occurred while initializing the installation:
System.IO.FileNotFoundException: Could not load file or assembly 'file:///D:\Some\Other\Working\Directory\MyService.exe' or one of its dependencies. The system cannot find the file specified..
This could be easily solved by using the full path to MyService.exe in the batch file:installutil /u C:\Program Files\MyProduct\MyService.exe
But what if my end user doesn't install my product in the default directory? I want the batch file to just look for MyService.exe in the same directory where the batch file itself is stored.
I knew that you can use variables like %1, %2, etc. to get the parameters passed into a batch file, and %0 to get the full name of the batch file itself -- but I didn't know that you could use modifiers on those variables to extract different pieces of the path.
In my service uninstaller, I need to get the path to the batch file, but exclude the batch file name. I can do that using %~dp0, which represents the drive and path portion of the file %0.%0 = C:\Program Files\MyProduct\uninstsvc.cmd
%~d0 = C:
%~p0 = \Program Files\MyProduct\
%~dp0 = C:\Program Files\MyProduct\
There are several other useful modifiers too: Using Batch Parameters. This ended up saving me a lot of time because I didn't have to make the application installer modify the batch file dynamically to include the full installation path. Sometimes you just can't beat a decent batch file. :)
Thursday, August 09, 2007
Getting a Batch File's Directory
Posted by
jwyse
at
1:11 AM
4
comments
Labels: Tips
Friday, July 06, 2007
Retrieving SQL Table Row Counts
I recently needed to get a quick row count from each table in a large SQL database, and I came across this post that shows two ways to do it. I'm pasting the SQL queries below; read the original post for more information.sp_msforeachtable "Print '?' select count(*) from ?"select convert(varchar(30),object_name(id)) [Table Name], rows from sysindexes
where object_name(id) not like 'sys%' and indid = 1
order by object_name(id)
Posted by
jwyse
at
1:47 PM
1 comments
Labels: Development, SQL, Tips
Monday, May 07, 2007
ForFiles Command
I just discovered a very useful command in Windows: ForFiles. It's used to iterate over files from the command prompt (and much easier to use than the for command, when it comes to manipulating files), and even processes some criteria.
I just used this command to cleanup old (/d -30; older than 30 days) gzipped (/m *.gz) files in the path (/p) e:\tempfiles and all subdirectories (/s). For each file, it issued the command (/c) to echo the filename to the command window (so I could see which files were being deleted) and then delete the file.forfiles /p e:\tempfiles /s /m *.gz /d -30 /c "cmd /c echo @file & del @file"
Check the Microsoft TechNet documentation for complete usage information and some more examples. If you don't already have the ForFiles command in your version of Windows (I know that it's included in Vista and Server 2003 SP1, but not XP SP2), you can get it from Microsoft's FTP site under the NT 4.0 "y2kfix" Resource Kit files.
[EDIT 2007.05.14: Apparently I posted the wrong MS FTP link. Thanks to Daniell for pointing this out and sending me the corrected link.]
Posted by
jwyse
at
10:13 AM
3
comments
Friday, May 04, 2007
HD Video Performance in Vista Media Center (Followup)
In my previous post, I said that I had updated drivers and tweaked some settings to get pretty good 720p video playback on my HTPC. My HTPC is a couple of years old, so I'm still running an Athlon XP 3200+, 1 GB RAM, and a GeForce FX 5500 GPU.
I wrote about my "success" after watching the first 5 minutes or so of the last episode of Heroes with perfect audio/video sync. I got too excited (and posted declaring victory) after too little testing. When I tried watching other 720p videos later, they still experienced A/V sync problems (although not nearly as bad as they were before I started).
Tonight I did some more research and testing, and found another codec that seems to have fixed this issue (for real this time!). I had been using CCCP, which includes ffdshow, which uses the libavcodec for H.264 video. CoreAVC is another codec that several sources claim is the fastest H.264 codec available, and is at lest 30% faster than the libavcodec that I had been using. The CCCP folks have a pretty good wiki entry about why CoreAVC isn't included in CCCP, and how to use CoreAVC instead of ffdshow.
I tried it out, benchmarking my FPS before and after registering the new codec. I used this post as a general guideline to do the benchmarks using Media Player Classic (included in CCCP) and Fraps. I used the same 720p and 1080p sample videos links in the post. The videos have a framerate of 23.976 fps. My results (average framerates) for the 720p sample video are below.
libavcodec: 17.402 fps
CoreAVC: 23.983 fps
My 720p videos play like any others now, and I can skip forward/back without losing A/V sync. The audio plays immediately after the skip, and the video catches up and re-syncs within a second or two. My CPU utilization is quite a bit lower now too (it was 100% using libavcodec).
Unfortunately, the CoreAVC codec isn't free like ffdshow, but it's still cheaper than upgrading hardware.
Posted by
jwyse
at
7:46 PM
0
comments
Labels: Media Center, Vista
Thursday, May 03, 2007
HD Video Performance in Vista Media Center
[Edited 2007.05.04: While I still recommend updating Windows/drivers/codecs anyway, it turns out that this didn't completely resolve my problem. Read my followup post for another codec option that performs much better and seems to have really resolved this issue.]
I was talking to James earlier this week about HD video in Media Center, and he warned me that 720p video performance is not that great (video is choppy and audio is out of sync) on his machine. He was giving me the heads-up because we have very similar HTPCs: I'm running Vista Ultimate on an Athlon XP 3200+; he's running XP MCE 2005 on an Athlon XP 2800+. Both have 1GB of dual-channel memory and similar (and quite modest) video cards.
I tried playing a 720p HD video on my machine tonight and saw exactly what he described, despite my slightly faster processor. My HTPC is a couple of years old, but it still runs great otherwise, so I'm not crazy about the idea of upgrading the hardware right now.
I was determined to squeeze acceptable performance out of my current hardware, so I started tweaking. I've now got the video running MUCH better, without any overclocking or outrageous settings (I even have Aero enabled). The video is smooth, and the audio and video are in sync, at least until I skip forward/back during playback -- and I suspect that a little bit more tweaking will fix that.
I took sort of a shotgun approach and changed quite a few things the first time around. All of these are changes that I wanted to make anyway, so I wasn't concerned with pinpointing which ONE change was the silver bullet.
- Added a 2GB USB flash drive and enabled ReadyBoost: Very noticeable improvement in the OS and Media Center interface, but no apparent changes to HD video playback.
- Ran Windows Update: There were no significant driver or Media Center-related updates available, but I needed to get the last batch of critical updates anyway. I don't think this had any effect on HD video playback.
- Updated my power settings from Power Saver (this must be the default, because I never would have chosen this option for an HTPC) to High Performance. In some configurations, the power settings throttle the CPU to conserve power, but since I don't have the AMD Cool 'n Quiet driver installed, I think it defaulted to maximum CPU power anyway.
- Verified that my memory was running in Dual Channel mode (it already was; no change here).
- Verified that I had the latest BIOS version installed (I already did; no change here).
- Updated CCCP (a pack of the most common audio/video codecs like DivX and Xvid) to the latest version.
- Stopped/disabled unused services like Indexing and Windows Firewall (the firewall was already "disabled," but the service was still running).
- Updated my video drivers to the latest version (Forceware 96.85, for my NVIDIA GeForce FX 5500).
I did a few quick tests along the way, and none of these changes noticeably improved playback until the last one: updating the video card drivers. The performance logs show that I still have very high CPU utilization during playback after these tweaks, but the audio/video is great now. I'd say perfect, but I need to do a little bit more tweaking so that I can fast-forward/rewind without getting the audio and video out of sync. Most of these changes should apply to both Vista and XP, and I'm curious to see if this fixes James' HD playback performance in XP MCE.
There are a couple more changes I can think of that might improve performance a bit more:
- Overclock the CPU/FSB/GPU in BIOS.
- Disable Windows themes (Aero/Luna): I'd expect a big improvement in most desktop applications, but I would hope that Windows isn't spending any CPU cycles rendering the theme while I have the Media Center application running full-screen anyway.
I've read some blog/forum posts that recommend setting the Enable Advanced Performance option in your disk write caching settings. This seems irrelevant (as far as video playback is concerned) because write caching shouldn't affect the disk read rate.* Disk access doesn't seem to be a factor in my case anyway, since I playback most of my TV shows from a mapped drive (a SATA disk in my server, mapped over my gigabit network). My tests tonight didn't show any difference between the network-mapped and local copies of the same video file.
A lot of this will depend on your hardware, but I read quite a few reports of people having this same problem with MUCH better hardware than what I'm running. Let me know if you have any other tips/recommendations to further improve HD video playback.
* At least not in my case, because this hard disk is dedicated to media, and no other processes are reading/writing to the disk while I'm playing video. If you have your media on disk shared with the OS or other applications, write caching might make a bit of difference for you.
Posted by
jwyse
at
12:12 AM
2
comments
Labels: Media Center, Vista
Blog Address Change
I've recently changed my blog address from jwyse.blogspot.com to blog.joshwyse.com.
You may want to update your links/RSS subscriptions to the new address to save yourself a redirect or two and speed up the loading of the page/feed.
Posted by
jwyse
at
12:01 AM
0
comments
Thursday, April 26, 2007
"Prepare this blank disk" in Vista
A few times recently I've popped a CD or DVD into one of my Vista machines, and it has popped up this message:
The only problem is... the disc in the drive wasn't blank. I've experienced this with at least two machines running Vista Business and Ultimate, 3 different CD-RW and DVD+/-RW drives, and at least a half dozen different professionally pressed CDs and DVDs -- so it wasn't a random read error or a dusty disc or anything like that.
Even more strange is the fact that I can "browse" the CD/DVD just fine from the command prompt using the good ol' dir and cd commands. This got me to the various setup.exe files that I was in a hurry to get to in the past, but tonight I took a few minutes to try to actually fix the problem.
Microsoft has a KB article that suggests some registry changes to the "lowerfilters" and "upperfilters" keys, but these didn't do anything for me.
The fix was pretty painless once I found it: just uninstall the affected devices from Device Manager and then Scan for Hardware Changes to re-detect them. It's a cheesy fix that should be entirely unnecessary, but it works, and it's easier than poking around in the registry.
I'd like to know more about the real underlying problem in Vista, but I'm not quite curious enough to track it down further since I've got my drives working properly now. If you happen to come across more information, please post a comment and let me know.
Posted by
jwyse
at
9:03 PM
16
comments
Sunday, March 18, 2007
Maintenance Plans in SQL 2005 Express
I use SQL Express on a few machines at home, and the one thing I'm missing in the Express Edition is the ability to automatically perform database backups/integrity checks/reindexing regularly with a Maintenance Plan. Since SQL Express doesn't have Maintenance Plans, it takes a bit of extra effort to set that up. Here's how I do it:
A Windows Scheduled Task runs daily, kicking off sqlexpressmaintplan.cmd:sqlcmd -S SQLSERVER\INSTANCE -i d:\scripts\sqlexpressmaintplan.sql
gzip -fNr e:\SQLBackups
(The second line simply compresses (using gzip) the .BAK files to conserve space.)
This executes sqlexpressmaintplan.sql, which has the configuration for my "maintenance plan". At a glance, it looks like a lot, but I've got it broken down into separate sections/tasks, so it's easy to comprehend and maintain.-- integrity check on system databases; save reports for 7 days
exec expressmaint
@database = 'ALL_SYSTEM',
@optype = 'CHECKDB',
@reportfldr = 'e:\SQLReports',
@rptretainunit = 'weeks',
@rptretainval = 1,
@report = 1
-- integrity check on user databases; save reports for 7 days
exec expressmaint
@database = 'ALL_USER',
@optype = 'CHECKDB',
@reportfldr = 'e:\SQLReports',
@rptretainunit = 'weeks',
@rptretainval = 1,
@report = 1
-- reindex my database; save reports for 7 days
exec expressmaint
@database = 'MyDatabase',
@optype = 'REINDEX',
@reportfldr = 'e:\SQLReports',
@rptretainunit = 'weeks',
@rptretainval = 1,
@report = 1
-- backup system databases; verify; save backups for 2 weeks; save reports for 7 days
exec expressmaint
@database = 'ALL_SYSTEM',
@optype = 'DB',
@backupfldr = 'e:\SQLBackups',
@reportfldr = 'e:\SQLReports',
@verify = 1,
@dbretainunit = 'weeks',
@dbretainval = 2,
@rptretainunit = 'weeks',
@rptretainval = 1,
@report = 1
-- backup user databases; verify; save backups for 4 weeks; save reports for 7 days
exec expressmaint
@database = 'ALL_USER',
@optype = 'DB',
@backupfldr = 'e:\SQLBackups',
@reportfldr = 'e:\SQLReports',
@verify = 1,
@dbretainunit = 'weeks',
@dbretainval = 4,
@rptretainunit = 'weeks',
@rptretainval = 1,
@report = 1
The real magic happens in the expressmaint stored procedure, created by SQL Server MVP Jasper Smith. (Also available as a standalone executable.) You can read more about this great tool on sqldbatips.com in two articles covering the stored procedure and the standalone app.
It's been a really long time since I originally set this up, and I'm having to revisit it now (and write about it) because I just rebuilt my primary workstation and server at home. Now that I'm reading back over this article, I can't remember why I chose to use the stored procedure instead of the executable version -- the exe would be a bit easier to drop into place, along with the batch file (the SQL script would no longer be necessary), next time I have to set this up on a fresh SQL Express install. I'm going to try out the executable version this time around to see if it's any easier to set up and maintain (it looks like it will be).
Thursday, March 08, 2007
Re-Arming Vista's Trial After Expiration
Windows Vista can be installed without a product key in a 30-day trial mode. This is nice for users who may want to try out Vista, or compare the different flavors (Home Basic, Home Premium, Business, Ultimate, etc). After 30 days, you are required to activate Vista by entering a valid product key, which will then lock it in to a particular edition depending on the key (Vista also supports instant upgrades, so you can change editions later).
As Jeff Atwood points out, you can extend the grace period to 120 days using the re-arm command. It's easy, it's legal, and it's provided by Microsoft. And ideally, you'll extend the grace period BEFORE the 30-day trial is up.
My Vista 30-day trial ran out on my media center PC, and I was given only four options the next time I tried to login: activate now, re-enter my license key, use reduced functionality mode, or logout. I'm not ready to activate, and I don't have a license key. I don't want to logout -- I want to watch TV! This leaves "reduced functionality mode," which is only an IE browser window (you're supposed to use it to buy Vista online). I remembered the re-arm command, but reduced functionality mode doesn't provide a Command Prompt, the Start Menu, Desktop, or anything else -- just a single IE window.
Fortunately, there's an easy workaround (or maybe several. Safe Mode seems like a reasonable option, but I didn't want to reboot). IE's address bar can be used to browse the file system to open web pages stored locally. It can also be used to launch c:\windows\explorer.exe, which starts up the rest of the Windows environment and gets you out of reduced-functionality mode. From there, I opened a command prompt with elevated privileges and ran "slmgr -rearm" to extend the trial period by another 30 days.
Posted by
jwyse
at
8:03 PM
3
comments
Wednesday, March 07, 2007
Visual Studio 2005 SP1 for Vista
Visual Studio 2005 Service Pack 1 is finally out of beta. Remember to uninstall the beta (listed under "updates" as Hotfix for Visual Studio 2005 [SKU name] - ENU (KB929470)) first.
Posted by
jwyse
at
12:11 PM
0
comments
Labels: .NET, Development, Vista, VS2005
Tuesday, February 13, 2007
Public Service Announcement: Back up Your Data
When a disk management or partition editing utility says you should back up your data before performing this operation, it's probably not joking. There's a pretty decent chance that this application will encounter error 1562 somewhere in the midst of merging your D and E partitions, leaving you with an unformatted drive and 135 GB of corrupt and unrecoverable data. Hypothetically.
If you're like me my overconfident friend, you might be somewhat lucky and only lose non-critical data like downloaded software, ISO images, and MP3s that you also have copies of on your portable MP3 player.
Should you find yourself in this unfortunate situation, I've had some success recovering data using the FindPart and FindNTFS utilities by Svend Olaf Mikkelsen. I've used those in the past to recover an entire partition from a hard disk with a corrupted partition table. These utilities were able to list and copy "my friend's" lost 135 GB of data yesterday, but unfortunately in this case, almost all the data was corrupt. At least the filenames tell which software/ISOs need to be downloaded again.
Posted by
jwyse
at
8:49 PM
2
comments
Labels: Tips
Sunday, February 11, 2007
Wake On LAN
I've recently upgraded both my home theater (media center) PCs to Windows Vista. The default power management settings put the HTPCs to sleep after some period of inactivity -- a feature I had disabled when I was running XP MCE on those machines. I usually don't let my machines "sleep" because I often access them remotely over the network.
Apparently I'm easily distracted, because my immediate need to copy a file to my sleeping HTPC sent me off on a 2-hour mission to write a little app that would utilize my PCs' Wake On LAN (WOL) capabilities. This started out as a simple WinForms app with a TextBox for input (MAC address) and a "Wake Up" button. That took about fifteen minutes, because I had to research how WOL works, and the "Magic Packet" that tells the PC to wake up (in a nutshell: the packet consists of 6 bytes of 0xFF followed by the remote PC's MAC address repeated 16 times, for a total of 102 bytes).
By then I was excited about how easy and cool WOL is, and what else I could do with the app. Anyway, a couple hours later, I ended up with a simple app that can be run from the command line or as a GUI app. I don't want to have to remember or lookup MAC addresses every time I want to wake up a PC, so the app can store MAC/hostname combinations. When run from the command line, I can pass in either the MAC address, or the hostname (which looks up the MAC stored in the file).
User Interface:


Command Line:
(Note that I'm using a MessageBox to confirm that the WOL packet has been sent. At one point I was doing the confirmation via the Console, but having the WinForms .exe switch gears to run as a console app, grabbing the current console for I/O, etc. was messy, and ended up doing weird things to the command prompt when it was done. One of these days I might try to get the console output working the way I want it to.)

The actual WOL process is very straightforward in .NET (I used C#); I just tacked on some other bells and whistles like associating hostnames to MACs, automatically saving the list to a file, and allowing it to be run as a GUI or command line app. I plan to clean up the code and release it at some point. In the meantime, let me know if you're interested.
...
I'm a bit behind on my blog reading, and I just saw Jeff Atwood's post from Friday: Remotely Waking Up Your PC. He posted about this very same subject, and apparently he got into it for the same reason (he wanted to wake up his Vista HTPC) -- just a day earlier. Weird. As expected, Atwood has some good stuff to say about WOL (refer to his post for how to set up the PC to respond to the WOL Magic Packet), but I enjoyed writing the app myself, so I guess I'm glad I didn't see his post until today.
Atwood's closing statement is perfect:
"You know, I think there's an inspiring moral to this story: why get out of your chair and walk 20 feet when you can spend two hours figuring out how to do it without moving at all? It's a symbolic victory for lazy people everywhere."
Posted by
jwyse
at
7:36 PM
1 comments
Labels: .NET, Development, Media Center, Tips, Vista
Wednesday, February 07, 2007
Building Directory Paths Dynamically
It's been a hellacious week year at the office so far.
<tangent>
Firefox's spiffy spellchecker thinks that 'hellacious' isn't a real word. It is. I was using the word instead of the less elegant alternative, 'helluva', but now that I've actually looked it up, I see that the definitions fit even better than I had intended. Particularly "formidably difficult" and "distasteful and repellant." We now return you to the blog post in progress.
</tangent>
Today's major issues revolved around a web application update that was deployed last night. The point of this post is to focus on just one of the specific issues and how it could have very easily been prevented. For the record, I'm not involved in the development or deployment of this application; I just stepped in today when SHTF.
The issue was that the application (an ASP.NET site written in C#) was looking for client-specific uploaded files in directories such as:D:\application\uploadsClientA
As you can probably guess, the ACTUAL paths were like this:D:\application\uploads\ClientA
This path was built dynamically in code by concatenating the upload destination (D:\application\uploads) stored in a configuration file with the name of the client currently logged in to the application (ClientA). This was done using basic string concatenation, and since the path in the config file didn't have a trailing slash, the resulting path did not exist.
The .NET Framework provides a very handy method in the System.IO namespace for building directory paths dynamically: Path.Combine(string path1, string path2). This method handles the insertion of slashes where needed, idiot-proofing the path concatenation without any extra code on your part. The developer's code SHOULD have looked something like this:string path = Path.Combine( Config["UploadDirectory"], clientname );
Then it wouldn't matter whether the UploadDirectory value in the config file had a trailing slash or not.
I guess the moral of the story is that the Framework is full of handy methods that handle many common scenarios and take out a lot of the guesswork (and reduce the amount of code YOU have to write and maintain). The trick is to find these methods and use them.
Posted by
jwyse
at
9:52 PM
1 comments
Labels: .NET, Development, Tips
Thursday, January 18, 2007
Windows Time
I've noticed that my Media Center PC's recordings haven't quite been aligned with the shows' time slots recently, and tonight I overcame laziness and actually looked into it just a bit. The PC's clock was off by just over a minute, which is about how late my recordings have been starting.
I've used apps like Atomic Clock Sync in the past, as a replacement/addition to the built-in Internet time synchronization in XP/2003. I usually prefer to keep things simple and just use built-in Windows functionality for these types of things, unless a third-party app really adds some value or features. In this case, the Windows time sync works, but I want it to check more often than the default setting (which appears to be 7 days on XP Pro, and 1 day on XP MCE). A minute or so isn't usually a big deal for most desktop applications, but for some (like media centers and most servers) it can make a big difference.
You can change the synchronization frequency pretty easily with a quick registry tweak:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient
Modify or add the DWORD named "SpecialPollInterval" and set the decimal value to the desired interval, in seconds (86400 = once per day; 3600 = once per hour). Then restart the W32Time service. You can verify the change on the Internet Time tab of the Date and Time Properties control panel window.
I've set mine to 7200 (2 hours), so hopefully my recordings will start and stop at the correct times now.
Posted by
jwyse
at
8:39 PM
1 comments
Labels: Media Center, Tips