|
A few months ago, a coworker needed a serial mouse for a side project, and was asking around for someone who still had one. I recalled not throwing away my old Appoint Mouse Pen—it has a PS/2 plug with a DE-9 adapter—so was able lend it. He returned the thing today, and just for kicks, we decided to see if it’d work with Vista.
It does.
The only trick was finding the manual way to add new mouse drivers—the Control Panel’s Add Hardware wouldn’t recognize it:
-
From the Computer Management Snap-in—right-click on Computer and select Manage—go to Device Manager.
-
Right-click on Mice and other pointing devices, and select Scan for hardware changes.
 |
|
A couple times a year, Vertigo supports a computer recycling drive. I happen to have a lot of old hard drives that I really wanted to give away, but not without wiping first. Not knowing how to do direct disk access in Win32, I was about to install an old compiler and implement something for DOS, invoking subfunction 7305h. Fortunately, in passing, I came across the Win32 function, CreateFile. Despite its name, CreateFile actually produces handles for accessing files [which don't have to be new]. Further, it can also target partitions and physical drives, passing in as the filename:
\.\PhysicalDriven - access hard disk n
\\.\s: - access partition s
These cases require full R/W access—the documentation states GENERIC_READ | GENERIC_WRITE is sufficient—and read and write sharing. So opening the x: partition for synchronous access would be: String fileName = L"\\.\x:";
pin_ptr pName = &(fileName->ToCharArray()[0]);
HANDLE hFile =
CreateFile(
L"\\.\x:",
FILE_ALL_ACCESS,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
pName = nullptr;
if (hFile == INVALID_HANDLE_VALUE)
{
if (GetLastError() == 0)
{
Throw Exception: Drive/partition does not exist.
}
else
{
Throw Exception: Can't open drive/partition.
}
}
The file handle can then then be wrapped in a SafeFileHandle so it can be closed with disposal: SafeFileHandle^ safeFileHandle = nullptr;
try
{
safeFileHandle =
gcnew SafeFileHandle((IntPtr)hFile, true); // Current thread owns handle.
...
}
finally
{
if (safeFileHandle != nullptr)
{
delete safeFileHandle;
}
}
In turn, this can be passed into a FileStream constructor, through which the actual I/O can be performed: // FileAccess::Read can be used for read access.
fileStream = gcnew FileStream(safeFileHandle, FileAccess::Write);
The FileStream is now available for writing [or reading]: fileStream->Write(
byteArray,
0,
byteArray->Length);
In addition, the FileStream's position can be changed: fileStream->Position = position;
Notes:
- While opening partitions and physical drives doesn't require Administrator access, many of the related I/O functions do—and for good reason!
- To get a physical disk's size, use the DeviceIOControl function, passing in IOCTL_DISK_GET_LENGTH_INFO:
DWORD bytesReturned;
GET_LENGTH_INFORMATION getLengthInformation;
if (FALSE == DeviceIOControl(
hFile,
IOCTL_DISK_GET_LENGTH_INFO.
NULL,
0,
&getLengthInformation,
sizeof(GET_LENGTH_INFORMATION),
&bytesReturned,
NULL))
{
Throw Exception: Can't get disk length
}
Int64 diskLength = getLengthInformation.Length.QuadPart;
- The DriveInfo class doesn't reveal a partition's full size—perhaps it takes file system overhead into account. To get a partition's length, use the DeviceIOControl function, passing in IOCTL_DISK_GET_PARTITION_INFO_EX:
DWORD bytesReturned;
PARTITION_INFORMATION_EX partitionInfo;
if (FALSE == DeviceIOControl(
hFile,
IOCTL_DISK_GET_PARTITION_INFO_EX,
NULL,
0,
&partitionInfo,
sizeof(PARTITION_INFORMATION_EX),
&bytesReturned,
NULL))
{
Throw Exception: Can't get partition info.
}
Int64 partitionLength = partitionInfo.PartitionLength.QuadPart;
- Partitions should be dismounted before writing, using the DeviceIOControl function with FSCTL_DISMOUNT_VOLUME:
DWORD bytesReturned;
if (FALSE == DeviceIoControl(
hFile,
FSCTL_DISMOUNT_VOLUME ,
NULL,
0,
NULL,
0,
&bytesReturned,
NULL))
{
Throw Exception: Partition can't be dismounted.
}
- It seems that you can't have partially-written sectors when you flush.
- I tested the direct physical disk and partition I/O on 32-bit Vista and XP, and was able to access IDE drives. However, I couldn't get the API's to work with my USB floppy drive.
- I never tested these API's with dynamic or encrypted partitions.
- While the interop will require more work, these API's can be accessed in C#. pinvoke.net has entries for CreateFile and DeviceIOControl.
- In most cases, a few random passes is probably good enough for wiping disks and partitions—be sure to use RNGCryptoServiceProvider or one of the CNG RNG algorithms as a source. For more security, patterns included in this article, targetting specific disk encodings, can be written instead.
- Needless to say, direct disk and partition I/O is inherently dangerous—though using the Win32 and .NET framework API's isn't as error-prone as the DOS interrupt ones. However, use them at your own risk. Also, be sure to implement a good, descriptive user confirmation before starting to write.
|
| A few people have posted this already—though for older versions of VS—but the Visual Studio XML editor will add IntelliSense if it can associate the file you’re editing with an XML schema. How it does this varies with the Visual Studio version, and in VS 9.0 (2008), stems from a file, named catalog.xml, located in the configured Caching/Schemas directory—it seems you can actually have multiple sets of IntelliSense configurations. This can be set through the Tools/Options menu under Text Editor/XML/Miscellaneous: It defaults to %VsInstallDir%\xml\Schemas. Opening a Visual Studio command prompt and typing: set VsInstallDir …should reveal the %VsInstallDir% that VS uses. The catalog.xml file’s SchemaCatalog/Association elements match .XSD files with extensions. Note that multiple schemas can be associated with particular extensions—you don’t have to edit the default .XSD files. Once you’ve saved catalog.xml, opening a file with the specified extension should include IntelliSense, reflecting its associated schema: Additionally, Microsoft provides some custom attributes for your .XSD file, specifying in more detail how Visual Studio should treat elements: http://msdn2.microsoft.com/en-us/library/aa713989(VS.71).aspx vs refers to the http://schemas.microsoft.com/Visual-Studio-Intellisense xml namespace. |
|
I got wind of this from Bruce Schneier’s Schneier on Security blog.
I’m primarily a PC user, and while I have machines with Firewire interfaces, I don’t have any devices that make use of them—I have lots of USB whatnots, though. According Wikipedia's Firewire entry one of the standard’s advantages over USB is that it has more capable interface hardware which can take the transfer management load off the CPU—perhaps SCSI vs. IDE is an apt analogy? I didn’t know is that these capabilities extend to DMA. This darkReading article sites an attack based on this feature, a Firewire device disabling a Windows machine’s password protection—Linux and OS X can be vulnerable as well.
The Wikipedia article reports that secure sites will either use machines that assign Firewire a virtual memory space (Power Mac G5's, Sun workstations), disable the hardware mapping between Firewire and memory, or not use Firewire at all. |
|
There doesn’t seem to be a whole lot about it online, but out of the box, ASP.NET’s included tool for enabling Polling-Based SQL Cache Dependencies doesn’t work with SQL 2005’s schema names. However, a few manually steps can get them to interoperate.
The problem is that a stored procedure that aspnet_regsql.exe calls, AspNet_SqlCacheRegisterTableStoredProcedure always precedes its trigger names with a dbo., and SQL 2005 believes that to be a schema name. To enable SQL Cache Dependencies on a table, you can either add an INSERT, UPDATE, DELETE trigger that calls AspNet_SqlCacheUpdateChangeIdStoredProcedure N’TableName’ yourself:
CREATE TRIGGER [dbo.SchemaName.TableName_AspNet_SqlCacheNotification_Trigger] ON [SchemaName].[TableName]
FOR INSERT, UPDATE, DELETE AS
BEGIN
SET NOCOUNT ON
EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure N'SchemaName.TableName'
END
…or hack AspNet_SqlCacheRegisterTableStoredProcedure, changing:
SET @fullTriggerName = 'dbo.[' + @triggerName + ']'
…to:
SET @fullTriggerName = '[dbo.' + @triggerName + ']'
…and then running aspnet_regsql.exe the normal way:
aspnet_regsql -U User -S Server -d Database -et -t SchemaName.TableName
In either case, be sure to confirm that ASP.NET recognizes your table as enabled for SQL cache dependencies:
aspnet_regsql -U User -S Server -d Database –lt
Note that even if you modify AspNet_SqlCacheUnRegisterTableStoredProcedure in a similar way, running:
aspnet_regsql -U User -S Server -d Database -dt -t SchemaName.TableName
…won’t delete the table’s trigger—however, it will get rid of the associated AspNet_SqlCacheTablesForChangeNotification row. Keeping in mind that the trigger inherits its table’s schema name, dropping it manually only requires:
DROP TRIGGER [SchemaName]. [dbo.SchemaName.TableName_AspNet_SqlCacheNotification_Trigger]
|
|

While Visual Studio 2005 includes a starter project for writing managed screen savers, it [the screen saver] doesn’t support display in the Screen Saver Settings dialog’s preview window, and isn’t built around WPF. As an exercise for learning WPF and WPF 3D—but also because I have a thing for screensavers—I put together a WPF-based library for this.
The WPF screen saver library contains much of its functionality in a System.Windows.Window child class. This provides a message loop to drive execution. In full-screen mode, it closes when the user presses a key or makes a significant mouse movement, and in preview mode, when its parent window is no longer displayed.
The API is fairly simple:
// Create a window, specifying a System.Windows.Media.Visual, parent window
// handle, and priority. For full-screen, the parent handle should be IntPtr.
// Zero. An UpdateScreenSaverStateHandler delegate can also be supplied, in
// case the visual's state needs updating--otherwise, it should be null. In
// preview mode, the window will check that its parent is still displayed by a
// frequency, based on the specified priority.
ScreenSaverWindow window =
new ScreenSaverWindow(
someVisual,
new UpdateScreenSaverStateHandler(someVisual.UpdateVisual),
somePriority,
parentHandle);
// Use that as the application's main window.
Application application = new Application();
application.Run(window);
Known Issues:
· ScreenSaverWindow can't actually display on the desktop root. Rather, it maximizes, using WindowStyle.None. Whether this will span multi-screen displays depends on how the OS is set to handle maximizing.
· The screen saver originally stored its settings in user/assembly Isolated Storage. However, when run due to inactivity under Vista—it worked fine under Server 2003 and in preview mode—it couldn’t read the settings file. Currently, the program saves to the user’s home path, but the Isolated Storage problem needs to be addressed.
· Like some—many?—WPF apps, the example implementation takes a bit longer to load than one might like. NGen helps, but doesn’t recognize the .scr file as an executable.
Source and binaries are available here.
The example implementation is a port of xscreensaver’s Lava Lite. The original source is available at http://www.jwz.org/xscreensaver/. Xscreensaver is Copyright (c) 2002-2004 Jamie Zawinski jwz@jwz.org.
The code for displaying in a preview window is based on Microsoft’s Create a Screensaver with GDI+ Code Sample.
Edit: Fixed the Download Link |
|
Duff’s device is a really neat construct for unrolling loops of indeterminate size. It was invented by Tom Duff during the early eighties (Duff's account) as a highly efficient way of copying memory, but can be used for other things too.
Basically, it repeats the processing code in batches—of 8, usually—and iterates over that total actions / batch size times. It consumes that quotient’s remainder with a switch statement’s fall through. Here’s that in C:
/*
* Divide by 8, rounding up. The switch will take care of
* the addition iteration. Count is the total number of
* iterations. It’s assumed to be greater than 0.
*/
int n = (count + 7) / 8;
while (--n > 0) {
Action
Action
Action
Action
Action
Action
Action
Action
}
/*
* Many compilers will use a jump table instead of a series of if
* statements if the case values are contiguous--the cases’ code
* will be contiguous and in order, to make fall through
* automatic.
*/
switch (count % 8) {
case 0:
Action
case 7:
Action
case 6:
Action
case 5:
Action
case 4:
Action
case 3:
Action
case 2:
Action
case 1:
Action
}
What makes the Duff’s device interesting is that it combines the loop and switch by exploiting C’s allowing do/while‘s to span cases:
/*
* The following is based on FOLDOC’s Duff’s device
* implementation: http://foldoc.org/?Duff%27s+device
* As before, count is assumed to be greater than 0.
*/
int n = (count + 7) / 8;
/* The mod is only performed during the first iteration. */
switch (count % 8) {
case 0:
do {
Action
case 7:
Action
case 6:
Action
case 5:
Action
case 4:
Action
case 3:
Action
case 2:
Action
case 1:
Action
} while (--n > 0);
}
While C# doesn’t allow do/while loops to span cases, it lets you use goto to navigate from one case to another—it forces you to do this if you want to fall through from a case that has at least one statement—so Duff’s device can also be implemented in managed code too:
// Count must be greater than 0.
int n = (count + 7) / 8;
switch (count % 8)
{
case 0:
Action
goto case 7;
case 7:
Action
goto case 6;
case 6:
Action
goto case 5;
case 5:
Action
goto case 4;
case 4:
Action
goto case 3;
case 3:
Action
goto case 2;
case 2:
Action
goto case 1;
case 1:
Action
// This differs from the other implementations’ conditional
// because in C#, == 0 and != 0 are faster than > 0, < 0, >=
// 0, and <= 0 (they're handled like Booleans).
if (--n != 0)
{
goto case 0;
}
break;
}
Is Duff’s device still relevant in an object-oriented world? If you have a task, comprised of quick, repeated actions—that aren’t already bottlenecked by database, disk, or network access—unrolling might help. And given that the C# compiler doesn’t seem to unroll loops automatically, you’ll need to implement it yourself. At least Duff’s device can provide a standard pattern for this.
For the heck of it, here’s a comparison between a loop and Duff’s device with the construct’s original purpose, copying memory. Note that this is just for illustrative purposes as Array.Copy generally performs better. Here’s the loop:
// destinationStartIndex - the first index in the destination
// array that should receive elements from the source array.
// sourceStartIndex – the first index in the source array that
// should be copied to the destination array.
while (count-- != 0)
{
destination[destinationStartIndex++] =
source[sourceStartIndex++];
}
Here’s how a Duff’s device performs.
Time [in ms.] to copy all indexes of an int32 array, 1000 iterations:
|
Array size |
|
|
4k |
8k |
16k |
32k |
64k |
128k |
256k |
|
Loop |
43 |
86 |
172 |
345 |
698 |
2684 |
6076 |
|
Duff's device |
28 |
55 |
109 |
217 |
465 |
2304 |
6066 |
As one might expect, Duff’s device copy performs better until memory access becomes a bottleneck—which is below 256k on my laptop, and your results will certainly vary.
Source, binaries, and annotated CIL asm are available at:
http://blogs.vertigosoftware.com/files/DuffDeviceTest.zip
Next up (hopefully), using a slightly modified Duff’s device as a [fake] threading mechanism.
For more information on Duff’s device, please check:
|
View in Web Browser /personal/davidb/Blog/_layouts/VisioWebAccess/VisioWebAccess.aspx?listguid={ListId}&itemid={ItemId}&DefaultItemOpen=1 0x0 0x1 FileType vdw 255 Compliance Details javascript:commonShowModalDialog('{SiteUrl}/_layouts/itemexpiration.aspx?ID={ItemId}&List={ListId}', 'center:1;dialogHeight:500px;dialogWidth:500px;resizable:yes;status:no;location:no;menubar:no;help:no', function GotoPageAfterClose(pageid){if(pageid == 'hold') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/hold.aspx?ID={ItemId}&List={ListId}'); return false;} if(pageid == 'audit') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/Reporting.aspx?Category=Auditing&backtype=item&ID={ItemId}&List={ListId}'); return false;} if(pageid == 'config') {STSNavigate(unescape(decodeURI('{SiteUrl}'))+'/_layouts/expirationconfig.aspx?ID={ItemId}&List={ListId}'); return false;}}, null); return false; 0x0 0x1 ContentType 0x01 898 Edit in Browser /_layouts/images/icxddoc.gif /personal/davidb/Blog/_layouts/formserver.aspx?XsnLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 FileType xsn 255 Edit in Browser /_layouts/images/icxddoc.gif /personal/davidb/Blog/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document 255 Edit in Browser /_layouts/images/icxddoc.gif /personal/davidb/Blog/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.2 255 Edit in Browser /_layouts/images/icxddoc.gif /personal/davidb/Blog/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.3 255 Edit in Browser /_layouts/images/icxddoc.gif /personal/davidb/Blog/_layouts/formserver.aspx?XmlLocation={ItemUrl}&OpenIn=Browser&Source={Source} 0x0 0x1 ProgId InfoPath.Document.4 255 View in Browser /personal/davidb/Blog/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsx 255 View in Browser /personal/davidb/Blog/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsm 255 View in Browser /personal/davidb/Blog/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType xlsb 255 View in Browser /personal/davidb/Blog/_layouts/xlviewer.aspx?id={ItemUrl}&DefaultItemOpen=1 0x0 0x1 FileType ods 255 Document Set Version History javascript:SP.UI.ModalDialog.ShowPopupDialog('{SiteUrl}/_layouts/DocSetVersions.aspx?List={ListId}&ID={ItemId}') 0x0 0x0 ContentType 0x0120D520 330 Send To other location javascript:GoToPage('{SiteUrl}/_layouts/docsetsend.aspx?List={ListId}&ID={ItemId}') 0x0 0x0 ContentType 0x0120D520 350 |
|
|
|
|