Spin Down Hard Disk Programmatically on Windows? - winapi

How do you request Windows to spin down a hard disk programmatically? Is there any user-mode function I can call (or kernel-mode function to call or IRP to send) in order to make this happen?
I've tried making a program to send an ATA STANDBY command directly to the hard disk, but the problem is that this method doesn't inform the system, and hence whenever the system needs to flush the cache, it'll wake up the hard disk again. How do I tell the system to do this for me? (If the system does it, it'll save up the cache and "burst" the data when it gets too large, instead of writing in small increments.)
(The entire point here is to do this directly, not by changing the system-wide spin-down timeout to a 1-second period and waiting for the disk to spin down. I need a function I can call at a specific moment in time when I'm using my laptop, not something generic that doesn't suit 95% of situations.)
How far I've gotten so far:
I have a feeling that PoCallDriver and IRP_MJ_POWER might be useful for this, but I have very limited kernel-mode programming experience (and pretty much zero driver experience) so I really have no idea.
Please read:
Update:
People seem to be repeatedly mentioning the solutions that I have already mentioned do not work. Like I said above, I've already tried "hacky" solutions that change the timeout value or that directly issue the drive a command, and the entire reason I've asked this question here is that those did not do what I needed. Please read the entire question (especially paragraphs 2 and 3) before repeating what I've already said inside your answers -- that's the entire difficulty in the question.
More info:
I've found this document about Disk Idle Detection to be useful, but my answer isn't in there. It states that the Power Manager sends an IRP to the disk driver (hence why I suspect IRP_MJ_POWER to be useful), but I have no idea how to use the information.

I hope this helps:
This: http://msdn.microsoft.com/en-us/library/aa394173%28VS.85%29.aspx
Leads to this:
http://msdn.microsoft.com/en-us/library/aa394132%28VS.85%29.aspx#properties
Then, you can browse to this:
http://msdn.microsoft.com/en-us/library/aa393485(v=VS.85).aspx
This documentation seems to outline what you are looking for I think.
P.S. Just trying to help, don't shoot the messanger.

Have you tried WMI? Based on MSDN documentation, you should be able to send spindown command to HDD via WMI:
http://msdn.microsoft.com/en-us/library/aa393493%28v=VS.85%29.aspx
uint32 SetPowerState(
[in] uint16 PowerState,
[in] datetime Time
);
EDIT:
This code lists all drives in system and drives that support this API:
strServer = "."
Set objWMI = GetObject("winmgmts://" & strServer & "/root\cimv2")
rem Set objInstances = objWMI.InstancesOf("CIM_DiskDrive",48)
Set objInstances = objWMI.ExecQuery("Select * from CIM_DiskDrive",,48)
On Error Resume Next
For Each objInstance in objInstances
With objInstance
WScript.Echo Join(.Capabilities, ", ")
WScript.Echo Join(.CapabilityDescriptions, ", ")
WScript.Echo .Caption
WScript.Echo .PNPDeviceID
WScript.Echo "PowerManagementCapabilities: " & .PowerManagementCapabilities
WScript.Echo "PowerManagement Supported: " & .PowerManagementSupported
WScript.Echo .Status
WScript.Echo .StatusInfo
End With
On Error Goto 0
Next
Just save this code as a .vbs file and run that from command line.

I do not have an answer to the specific question that Mehrdad asked.
However, to help others who find this page when trying to figure out how to get their disk to standby when it should but doesn't:
I found that on a USB disk, MS PwrTest claims that the disk is off, but actually it is still spinning. This occurs even with really short global disk timeouts in win 7. (This implies that even if the system thinks it has turned the disk off, it might not actually be off. Consequently, Mehrdad's original goal might not work even if the correct way to do it is found. This may relate to how various USB disk controllers implement power state.)
I also found that the program HDDScan successfully can turn off the disk, and can successfully set a timeout value that the disk honors. Also, the disk spins up when it is accessed by the OS, a good thing if you need to use it, but not so good if you are worrying about it spinning up all the time to flush 1kB buffers. (I chose to set the idle timeout in HDDScan to 1 minute more than the system power manager timeout. This hopefully assures that the system will not think the disk is spun up when it is not.)
I note that powercfg has an option to prevent the idle clock from restarting from small infrequent disk writes. (Called "burst ignore time.")
You can get HDDScan here: HDDScan.com and PwrTest here: Windows Driver Kit. Unfortunately, the PwrTest thing forces you to have a lot of other MS stuff installed first, but it is all free if you can figure out how to download it from their confusing web pages.

While there is no apparent way to do what you're asking for (i.e. tell power management "act as if the timer for spinning down the disk has expired"), there may be a couple ways to simulate it:
Call FlushFileBuffers on the drive (you need to be elevated to open \\.\C), then issue the STANDBY command to the drive.
Make the API call that sets the timeout for spinning down the disk to 1 second, then increase it back to its former value after 1 second. Note that you may need to ramp up to the former value rather than immediately jump to it.

I believe the Devcon Command line utility should be able to accomplish what you need to do. If it does - the source code is available in the Windows Ddk.

Related

How to detect programmatically when the OS has done loading all of its applications\services?

Edit: I rephrased my question, please ignore all of the comments below (up to the 7th of May).
First off, I'll try to explain the problem:
My process is trying to show a Deskband programmatically using ITrayDeskBand::ShowDeskBand.
It works great at any time except for when the OS is loading all of its processes (after reset or logout).
After Windows boots and starts loading the various applications\services, the mouse cursor is set to wait for a couple of seconds (depends on how many applications are running \ how fast everything is).
If the mouse cursor is set to wait and the process is running during that time, the call will fail.
However, if my process waits a few seconds (after that time the cursor becomes regular) and then invokes the call, everything works great.
This behavior was reproduced both on Windows 7 and Windows Vista.
So basically what I'm asking is :
1) Just for basic knowledge, What the OS does when the cursor is set to busy?
2) The more important question : How can i detect programmatically when this process is over?
At first, I thought that explorer hadn't loaded properly so I've used WaitForInputIdle but it wasn't it.
Later I thought that the busy cursor indicates that the CPU is busy so I've created my process using IDLE_PRIORITY_CLASS but idle times were received while the cursor was busy.
Windows never stops loading applications and/or services!
As a matter of fact, applications come and go, some of these interactively some of these without any user interaction. Even Services are loaded at different points of time (depending on their settings and the external conditions - e.g the Smard Card Resource Manager Service might start only when the OS detects that a Smard Card device has connected). Applications can (but must not) stop automatically so do some Services.
One never knows when Windows has stop to load ALL applications and/or Services.
If ITrayDeskBand::ShowDeskBand fails, then wait for the TaskbarCreated message and then try again. (This is the same technique used by notification icons.)
The obvious approach would be to check whether ShowDeskband worked or not, and if not, retry it after a few seconds. I'm assuming you've already considered and rejected this option.
Since you seem to have narrowed down the criteria to which cursor is being displayed, how about waiting for the particular cursor you are wanting? You can find which cursor is being shown like this:
CURSORINFO cinfo;
ICONINFOEX info;
cinfo.cbSize = sizeof(cinfo);
if (!GetCursorInfo(&cinfo)) fail();
info.cbSize = sizeof(info);
if (!GetIconInfoEx(cinfo.hCursor, &info)) fail();
printf("szModName = %ws\n", info.szModName);
printf("wResID = %u\n", info.wResID);
Most of the simple cursors are in module USER32. The relevant resource IDs are listed in the article on GetIconInfo.
You apparently want to wait for the standard arrow cursor to appear. This is in module USER32, and the resource ID is 32512 (IDC_ARROW).
I suggest that you check the cursor type ten times a second. When you see the arrow cursor ten times in a row (i.e., for a full second) it is likely that Explorer has finished starting up.

Windows 7 file problem

I am using VB6 SP6
This code has work correctly for years but I am now having a problem on a WIN7 to WIN7 network. It also works correctly on an XP to Win7 network.
Open file for random as ChannelNum LEN =90
'the file is on the other computer on the network
RecNum = (LOF(ChannelNum) \ 90) + 2
Put ChannelNum, RecNum, MyAcFile
'(MyAcFile is UDT that is less than 90 long)
.......... other code that does not reference file or RecNum - then
RecNum = (LOF(ChannelNum) \ 90) + 2
Put ChannelNum, RecNum, MyAcFile
Close ChannelNum
The second record overwrites the first.
We had a similar problem in the past with OpportunisticLocking so we turn that off at install - along with some other keys that cause errors in data in Windows networks.
However we have had no problems like this for years, so I think MS have some new "better" option that they think will "improve" networking.
Thanks for your help
I doubt there is any "bug" here except in your approach. The file metadata that LOF() interrogates is not meant to be updated immediately by simple writes. A delay seems like a silly idea, prone to occasional failure unless a very long delay is used and sapping performance at best. Even close/reopen can be iffy: VB6's Close statement is an async operation. That's why the Reset statement exists.
This is also why things like FlushFileBuffers() and SetEndOfFile() exist at the API level. They are also relatively expensive operations from a performance standpoint.
Track your records yourself. Only rely on LOF() if necessary after you first open the file.
Hmmm... is file (as per in the open statement at the top of the code sample) UNC filename or similar to x:\ where x is the mapped drive? Are you not incrementing RecNum? Judging by the code, the RecNum is unchanged and hence appears to overwrite the first record...Sorry for sounding ummm no pun intended... basic...It would be of help to show some more code here...
Hope this helps,
Best regards,
Tom.
It can be just timing issue. In some runs your LOF() function returns more updated information than in other runs. The file system API is asynchronous, for example when some write function is called it will not be immediately reflected as the increazed size.
In short: you code have shown an old bug, which is just easier to reproduce on Windows 7.
To fix the bug the cheapest way: you may decide to add a delay (it can be significant delay of say 5 seconds).
More elaborate fix is to force the size update by closing and reopening file.

Force windows to refresh a disk FAT [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I have a separate partition on my disk formatted with FAT32. When I hibernate windows, I want to be able to load another OS, create/modify files that are on that partition, then bring Windows out of hibernation and be able to see the changes that I've made.
I know what you're going to type, "Well, you're not supposed to do that!" and then link me to some specs about how what I'm trying to do is wrong/impossible/going to break EVERYTHING. However, I'm sure there's some way I can get around that. :)
I don't need the FAT32 partition in Windows, except to read the files that were written there, then I'm done - so whatever the solution is, it's acceptable for the disk to be completely inaccessible for a period of time. Unfortunately, I can't take the entire physical disk offline because it is just a partition of the same physical device that windows is installed on -- just the partition.
These are the things I've tried so far...
Google it. I got at least one "this is NEVER going to happen" answer. Unacceptable! :)
Unmount the disk before hibernating. Mount after coming out of hibernation. This seems to have no effect. Windows still thinks the FAT is the same as it was before, so whatever data I wrote to disk is lost, and any files I resized are corrupted. If any of the file was cached, it's even worse.
Use DeviceIoControl to call IOCTL_DISK_UPDATE_PROPERTIES to try and refresh the disk (but the partition table hasn't changed, so this doesn't really do anything).
Is there any way to invalidate the disk/volume read cache to force windows to go back to the disk?
I thought about opening the partition and reading/writing directly by using libfat and bypassing the cache or something is overkill.
So I finally got a solution to my problem. In my mind, I associated Mount Point with Mount. These are NOT the same thing. Removing all of the volume mount points does not make the volume unmounted. It's still mounted but not in the sense that you have a path you can access in explorer.
This is the article that started it all.
It also goes to show that searching for your EXACT problem, as opposed to the perceived problem can help a lot!
So there were a couple of solutions, one was to constantly call NtSetSystemInformation() in a tight loop to set the "SYSTEMCACHEINFORMATION" property to essentially empty/clear the cache whenever the system is going to hibernation. Then stop the loop when you come out. This, to me, seemed like it could affect system performance. So I discarded it.
Even better though, is the recommended solution to a slightly different problem presented in this MSDN article, which provides direction to an even better solution to the problem: Dismounting Volumes in a Hibernate Once/Resume Many Configuration
Now I have a service which will flush the write caches, then lock and dismount the volume whenever the system goes into hibernation/sleep and release the lock on the volume as soon as it comes out.
Here's a little bit of code.
OnHibernate>
volumeHandle = CreateFile(volumePath,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0 );
FlushFileBuffers( volumeHandle );
DeviceIoControl( volumeHandle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &cbReturned, NULL ) ;
DeviceIoControl( volumeHandle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &cbReturned, NULL );
//Keep the handle open here.
//System hibernates.
OnResume>
DeviceIoControl( volumeHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &cbReturned, NULL )
CloseHandle(volumeHandle)
Hopefully this helps someone else out in the future :)
Well, you're not supposed to do that! ;-)
Since the operating system (Windows in this case, but Linux is the same) writes some of its internal filesystem structures in the hibernation image, it is going to be very confused if the disk contents change while it's "running" (think of hibernation as just a long pause in the operating system's execution).
What I can suggest is that you completely bypass the issue: format the partition as ext2. There are Windows programs to read an ext2 partition, which you can use to get data out of it, and most modern operating systems should be able to read/write it (since it's a quite common Unix-style filesystem). Avoid ext2 IFS drivers; you want to take the filesystem access out of the kernel and into a program which you can open and close at will.
Use Linux to create the partition as a hidden FAT32 partition. Linux will let you mount the partition and write files. Windows will not let you mount the partition and read files, and Windows will not corrupt the partition. But there are third party libraries that will read the partition while Windows is running.
To clarify, hidden means that the partition type is different from an ordinary FAT32 partition type. If your ordinary partition type is 0x0C then the corresponding hidden type is 0x1C.
On a related but different problem, I used the following:
Running cmd as administrator (works from batch file)
DISKPART
SELECT G
REMOVE
ASSIGN LETTER=G
EXIT
This unmounts the volume (G:) and then remounts it. Any read of the disk (in my case a device pretending to be a USB Mass Storage Device formatted as FAT16) will actually read the device, so the read cache is effectively flushed.
Downside is that starting DISKPART takes about 4 seconds, but that's probably not a problem in a hibernating situation.
My memory is that the FAT table is read during the OS boot and mounting of the volume. Can't you do a shutdown, then modify the FAT, then reboot Windows?
As far as I can tell, Windows does caching at the disk level. However, if a partition has a type that Windows refuses to read or write (ext2, hidden FAT32, etc.) then that partition's contents should never get into Windows caches in the first place.
With DOS, it was typing ctrl+c, twice if I recall well.
With Linux, sync; echo 3 > /proc/sys/vm/drop_caches or a script thereof, of course ;-)
With Windows, interpolate ;-) Or install VirtualBox and Ubuntu+Wine to develop compatibly.
Well, I vaguely remember that former Windows used a diskcache program to start a process and that diskcache could be used to send the process a signal to flush and purge the whole cache. If things have evolved gently, you might be able to send such a signal to a Windows process. Sorry I'm no longer using Windows partly because of such obscurity.

Recovery from optical media ignoring read errors

I have backups of files archived in optical media (CDs and DVDs). These all have par2 recovery files, stored on separate media. Even in cases where there are no par2 files, minor errors when reading on one optical drive can be read fine on another drive.
The thing is, when reading faulty media, the read time is very, very long, because devices tend to retry multiple times.
The question is: how can I control the number of retries (ie set to no retries or only one try)? Some system call? A library I can download? Do I have to work on the SCSI layer?
The question is mainly about Linux, but any Win32 pointers will be more than welcome too.
man readom, a program that comes with cdrecord:
-noerror
Do not abort if the high level error checking in readom found an
uncorrectable error in the data stream.
-nocorr
Switch the drive into a mode where it ignores read errors in
data sectors that are a result of uncorrectable ECC/EDC errors
before reading. If readom completes, the error recovery mode of
the drive is switched back to the remembered old mode.
...
retries=#
Set the retry count for high level retries in readom to #. The
default is to do 128 retries which may be too much if you like
to read a CD with many unreadable sectors.
The best tool avaliable is dd_rhelp. Just
dd_rhelp /dev/cdrecorder /home/myself/DVD.img
,take a cup of tea and watch the nice graphics.
The dd_rhelp rpm package info:
dd_rhelp uses ddrescue on your entire disc, and attempts to gather the maximum
valid data before trying for ages on badsectors. If you leave dd_rhelp work
for infinite time, it has a similar effect as a simple dd_rescue. But because
you may not have this infinite time, dd_rhelp jumps over bad sectors and rescue
valid data. In the long run, it parses all your device with dd_rescue.
You can Ctrl-C it whenever you want, and rerun-it at will, dd_rhelp resumes the
job as it depends on the log files dd_rescue creates. In addition, progress
is shown in an ASCII picture of your device being rescued.
I've used it a lot myself and Is very, very realiable.
You can install it from DAG to Red Hat like distributions.
Since dd was suggested, I should note that I know of the existence and have used sg_dd, but my question was not about commands (1) or (1m), but about system calls (2) or libraries (3).
EDIT
Another linux command-line utility that is of help, is sdparm. The following flag seems to disable hardware retries:
sudo sdparm --set=RRC=0 /dev/sr0
where /dev/sr0 is the device for the optical drive in my case.
While checking whether hdparm could modify the number of retries (doesn't seem so), I thought that, depending on the type of error, lowering the CD-ROM speed could potentially reduce the number of read errors, which could actually increase the average read speed. However, if some sectors are completely unreadable, then even lowering the CD-ROM speed won't help.
Since you are asking about driver level access, you should look into SCSI commands, or perhaps an ASPI like API. On windows VSO software (developers of blindread/blindwrite below) have developed a much better API, Patin-Couffin, that provides locked low level access:
http://en.wikipedia.org/wiki/Patin-Couffin
That might get you started. However, at the end of the day, the drive is interfaced with SCSI commands, even if it's actually USB, SATA, ATA, IDE, or otherwise. You might also look up terms related to ATAPI, which was one of the first specifications for this CD-ROM SCSI layer interface.
I'd be surprised if you couldn't find a suitable linux library or example of dealing with the lower level commands using the above search terms and concepts.
Older answer:
Blindread/blindwrite was developed in the heyday of cd-rom protection schemes often using intentionally bad sectors or error information to verify the original CD.
It will allow you to set a whole slew of parameters, including retries. Keep in mind that the CD-ROM drive itself determines how many times to retry, and I'm not sure that this is settable via software for many (most?) CD-ROM drives.
You can copy the disk to ISO format, ignoring the errors, and then use ISO utilities to read the data.
-Adam
Take a look at the ASPI interface. Available on both windows and linux.
dd(1) is your friend.
dd if=/dev/cdrom of=image bs=2352 conv=noerror,notrunc
The drive may still retry a bit, but I don't think you'll get any better without modifying firmware.

Copying Files over an Intermittent Network Connection

I am looking for a robust way to copy files over a Windows network share that is tolerant of intermittent connectivity. The application is often used on wireless, mobile workstations in large hospitals, and I'm assuming connectivity can be lost either momentarily or for several minutes at a time. The files involved are typically about 200KB - 500KB in size. The application is written in VB6 (ugh), but we frequently end up using Windows DLL calls.
Thanks!
I've used Robocopy for this with excellent results. By default, it will retry every 30 seconds until the file gets across.
I'm unclear as to what your actual problem is, so I'll throw out a few thoughts.
Do you want restartable copies (with such small file sizes, that doesn't seem like it'd be that big of a deal)? If so, look at CopyFileEx with COPYFILERESTARTABLE
Do you want verifiable copies? Sounds like you already have that by verifying hashes.
Do you want better performance? It's going to be tough, as it sounds like you can't run anything on the server. Otherwise, TransmitFile may help.
Do you just want a fire and forget operation? I suppose shelling out to robocopy, or TeraCopy or something would work - but it seems a bit hacky to me.
Do you want to know when the network comes back? IsNetworkAlive has your answer.
Based on what I know so far, I think the following pseudo-code would be my approach:
sourceFile = Compress("*.*");
destFile = "X:\files.zip";
int copyFlags = COPYFILEFAILIFEXISTS | COPYFILERESTARTABLE;
while (CopyFileEx(sourceFile, destFile, null, null, false, copyFlags) == 0) {
do {
// optionally, increment a failed counter to break out at some point
Sleep(1000);
while (!IsNetworkAlive(NETWORKALIVELAN));
}
Compressing the files first saves you the tracking of which files you've successfully copied, and which you need to restart. It should also make the copy go faster (smaller total file size, and larger single file size), at the expense of some CPU power on both sides. A simple batch file can decompress it on the server side.
Try using BITS (Background Intelligent Transfer Service). It's the infrastructure that Windows Update uses, is accessible via the Win32 API, and is built specifically to address this.
It's usually used for application updates, but should work well in any file moving situation.
http://www.codeproject.com/KB/IP/bitsman.aspx
I agree with Robocopy as a solution...thats why the utility is called "Robust File Copy"
I've used Robocopy for this with excellent results. By default, it will retry every 30 seconds until the file gets across.
And by default, a million retries. That should be plenty for your intermittent connection.
It also does restartable transfers and you can even throttle transfers with a gap between packets assuing you don't want to use all the bandwidth as other programs are using the same connection (/IPG switch)?.
How about simply sending a hash after or before you send the file, and comparing that with the file you received? That should at least make sure you have a correct file.
If you want to go all out you could do the same process, but for small parts of the file. Then when you have all pieces, join them on the receiving end.
You could use Microsoft SyncToy (free).
http://www.microsoft.com/Downloads/details.aspx?familyid=C26EFA36-98E0-4EE9-A7C5-98D0592D8C52&displaylang=en
Hm, seems rsync does it, and does not need server/daemon/install I thought it does - just $ rsync src dst.
SMS if it's available works.

Resources