CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Oct 2008
    Posts
    6

    Turn off the hard disk through WMI

    Dear all:

    I want to turn off the hard disk through program.
    Reference to the SetPowerState function of WMI CIM_DiskDrive Class and the following URL
    http://msdn.microsoft.com/en-us/libr...21(VS.85).aspx ,
    I write a VC6 programe,but encountered problem.

    1.Can SetPowerState really realize turn off the hard disk?
    Platform SDK says "Defines the desired power state for a logical device
    and when a device should be put into that state. Not implemented by WMI."
    What is "Not implemented by WMI" mean?

    2.When called pClassInstance->Put(L"PowerState", ...),it failed,return value is "WBEM_E_TYPE_MISMATCH",but refer to Platform SDK,datatype of "PowerState" is VT_UI2.
    I'm puzzled.

    3. If SetPowerState can realize turn off the hard disk,
    how can I realize control a single disk if I have two or more disk in my system?

    Thanks
    Best Regards
    Frankzcj


    Relevant code as below:

    IWbemServices *pSvc;
    HRESULT hres;

    .....
    BSTR MethodName = SysAllocString(L"SetPowerState");
    BSTR ClassName = SysAllocString(L"CIM_DiskDrive");

    IWbemClassObject* pClass = NULL;
    hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);

    IWbemClassObject* pInParamsDefinition = NULL;
    hres = pClass->GetMethod(MethodName, 0, &pInParamsDefinition, NULL);

    IWbemClassObject* pClassInstance = NULL;
    hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);

    // Create the values for the in parameters
    VARIANT varPowerState;
    varPowerState.vt = VT_UI2;
    varPowerState.uiVal = 6;
    // Store the value for the in parameters
    hres = pClassInstance->Put(L"PowerState", 0,&varPowerState, 0);

    VARIANT varDate;
    varDate.vt = VT_DATE ;
    varDate.uiVal = 0;
    // Store the value for the in parameters
    hres = pClassInstance->Put(L"Time", 0,&varDate, 0);

    IWbemClassObject* pOutParams = NULL;
    hres = pSvc->ExecMethod(ClassName, MethodName, 0,NULL, pClassInstance, &pOutParams, NULL);

    ......

  2. #2
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Turn off the hard disk through WMI

    >> 1.Can SetPowerState really realize turn off the hard disk?
    Probably not. Unless you have a custom provider intalled...
    http://msdn.microsoft.com/en-us/libr...85(VS.85).aspx
    Quote Originally Posted by MSDN
    This method is currently not implemented by WMI. To use this method, you must implement it in your own provider.
    >> 2. ... it failed, ... I'm puzzled
    It's probably because WMI does not "implement" CIM_DiskDrive. You should be using the Win32_* derived classes instead. In this case, Win32_DiskDrive.

    >> 3. ... how can I realize control a single disk if I have two or more disk in my system?
    The example code you linked to used Win32_Process.Create(). This method does not require an "instance" of a Win32_Process. In other words, you don't need a Win32_Process object that represents a currently running process in order to call the Create() method. If you were to call Win32_Process.Terminate(), then the object would need to be a real instance (representing a real process).

    The first parameter to ExecMethod() takes an object path. Here is where you specify an object instance using the "key" object property to uniquely identify it.
    http://msdn.microsoft.com/en-us/libr...50(VS.85).aspx
    A typical way of doing this is to SELECT the current instances in the system, then get the "__Path" property to get the full pathname of the object instance.

    gg

  3. #3
    Join Date
    Oct 2008
    Posts
    6

    Re: Turn off the hard disk through WMI

    Thank you,Codeplug.
    Please see bellow.

    >>Probably not. Unless you have a custom provider intalled...

    This mean that I must define the SetPowerState function myself?
    Well,how can I do this,can you show me a sample or URL link?



    >> You should be using the Win32_* derived classes instead. In this case, Win32_DiskDrive.

    I used Win32_DiskDrive instead, but result is the same,"WBEM_E_TYPE_MISMATCH".


    >> A typical way of doing this is to SELECT the current instances in the system, then get the "__Path" property to get the full pathname of the object instance.

    I noticed that for CIM_DiskDrive or Win32_DiskDrive class,"DeviceID" is the "key" object property.
    So if I have two disks in my system,after select,I can get DeviceID such as
    "\\.\PHYSICALDRIVE0" and "\\.\PHYSICALDRIVE0".
    If I want to turn off the first disk,
    then how can I use "\\.\PHYSICALDRIVE0" to generate the first parameter to ExecMethod()?
    Could you give me a detail?Thank you.

  4. #4
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Turn off the hard disk through WMI

    Forget about WMI - it won't do what you want.
    The best you can do is change the power policy for when disks should spin-down.
    Code:
    #include <ntstatus.h>
    #define WIN32_NO_STATUS
    #include <windows.h>
    #include <powrprof.h>
    
    #include <iostream>
    using namespace std;
    
    #pragma comment(lib, "PowrProf.lib")
    
    //------------------------------------------------------------------------------
    
    #define GetPowerInformation(policy, pStruct) \
        CallNtPowerInformation(policy, 0, 0, (PVOID)pStruct, sizeof(*pStruct))
    
    #define SetPowerInformation(policy, pStruct) \
        CallNtPowerInformation(policy, (PVOID)pStruct, sizeof(*pStruct), 0, 0)
    
    //------------------------------------------------------------------------------
    // Check admin limits for spindown settings - you must have sufficient 
    // privileges in order to change these settings
    LONG EnsureSpindownWithinAdminPolicy(ULONG timeoutSecs)
    {
        ADMINISTRATOR_POWER_POLICY app;
        LONG status = GetPowerInformation(AdministratorPowerPolicy, &app);
        if (status != STATUS_SUCCESS)
            return status;
    
        bool bChangeAdminPolicy = false;
        if (timeoutSecs < app.MinSpindownTimeout)
        {
            app.MinSpindownTimeout = timeoutSecs;
            bChangeAdminPolicy = true;
        }//if
    
        if (timeoutSecs > app.MaxSpindownTimeout)
        {
            app.MaxSpindownTimeout = timeoutSecs;
            bChangeAdminPolicy = true;
        }//if
    
        if (bChangeAdminPolicy)
        {
            status = SetPowerInformation(AdministratorPowerPolicy, &app);
            if (status != STATUS_SUCCESS)
                return status;
        }//if    
    
        return STATUS_SUCCESS;
    }//EnsureSpindownWithinAdminPolicy
    
    //------------------------------------------------------------------------------
    // Get the information you see in the Control Panel "Power Options" applet.
    LONG PwMgmt_GetCurrentPowerPolicy(POWER_POLICY &pp)
    {
        UINT scheme;
        if (!GetActivePwrScheme(&scheme))
        {
            DWORD le = GetLastError();
            if (!le)
                return ERROR_UNHANDLED_ERROR;
            return le;
        }//if
    
        if (!ReadPwrScheme(scheme, &pp))
        {
            DWORD le = GetLastError();
            if (!le)
                return ERROR_UNHANDLED_ERROR;
            return le;
        }//if
    
        return STATUS_SUCCESS;
    }//PwMgmt_GetCurrentPowerPolicy
    
    //------------------------------------------------------------------------------
    // Permanently set spindown timeout for current power scheme
    // NOTE: Does not affect laptops on DC (battery) power
    LONG PwMgmt_SetSpindownTimeoutPerm(ULONG timeoutSecs)
    {
        // ensure the timeout is within the admin policy range
        LONG status = EnsureSpindownWithinAdminPolicy(timeoutSecs);
        if (status != STATUS_SUCCESS)
            return status;
    
        UINT scheme;
        if (!GetActivePwrScheme(&scheme))
        {
            DWORD le = GetLastError();
            if (!le)
                return ERROR_UNHANDLED_ERROR;
            return le;
        }//if
    
        POWER_POLICY pp;
        if (!ReadPwrScheme(scheme, &pp))
        {
            DWORD le = GetLastError();
            if (!le)
                return ERROR_UNHANDLED_ERROR;
            return le;
        }//if
    
        pp.user.SpindownTimeoutAc = timeoutSecs;
    
        if (!SetActivePwrScheme(scheme, 0, &pp))
        {
            DWORD le = GetLastError();
            if (!le)
                return ERROR_UNHANDLED_ERROR;
            return le;
        }//if
    
        return 0;
    }//PwMgmt_SetSpindownTimeoutPerm
    
    //------------------------------------------------------------------------------
    // Temporarily set spindown timeout for current power scheme
    // NOTE: If you look at it in control panel, it will become permanent, even if 
    //       you hit cancel. Otherwise original settings will revert after a reboot.
    // NOTE: Does not affect laptops on DC (battery) power
    LONG PwMgmt_SetSpindownTimeoutTemp(ULONG timeoutSecs)
    {
        // ensure the timeout is within the admin policy range
        LONG status = EnsureSpindownWithinAdminPolicy(timeoutSecs);
        if (status != STATUS_SUCCESS)
            return status;
    
        SYSTEM_POWER_POLICY spp;
        status = GetPowerInformation(SystemPowerPolicyAc, &spp);
        if (status != STATUS_SUCCESS)
            return status;
    
        spp.SpindownTimeout = timeoutSecs;
    
        status = SetPowerInformation(SystemPowerPolicyAc, &spp);
    
        return status;
    }//PwMgmt_SetSpindownTimeoutTemp
    
    //------------------------------------------------------------------------------
    
    int main()
    {
        LONG status;
        POWER_POLICY pp;
    
        status = PwMgmt_GetCurrentPowerPolicy(pp);
        if (status != STATUS_SUCCESS)
        {
            cerr << "PwMgmt_GetCurrentPowerPolicy failed, " << status << endl;
            return status;
        }//if
    
        cout << "Current SpindownTimeoutAc = ";
        if (pp.user.SpindownTimeoutAc)
             cout << pp.user.SpindownTimeoutAc << " secs" << endl;
        else
            cout << "Never/Disabled" << endl;
    
        ULONG newSpindown = 60 * 30; // 30 minutes
    
        status = PwMgmt_SetSpindownTimeoutPerm(newSpindown);
        //status = PwMgmt_SetSpindownTimeoutTemp(newSpindown);
    
        if (status != STATUS_SUCCESS)
        {
            cerr << "Failed to set SpindownTimeoutAc to " << newSpindown 
                 << ", " << status << endl;
            return status;
        }//if
    
        cout << "Set SpindownTimeoutAc to " << newSpindown << endl;
    
        return 0;
    }//main
    gg

  5. #5
    Join Date
    Jan 2008
    Posts
    48

    Re: Turn off the hard disk through WMI

    Quote Originally Posted by Codeplug
    Forget about WMI - it won't do what you want.
    The best you can do is change the power policy for when disks should spin-down.
    No.
    The 2 right methods are WMI and an undocumented api call
    Never change GPP, it's a global parameter

  6. #6
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Turn off the hard disk through WMI

    >> No. The 2 right methods are WMI and an undocumented api call
    Are you keeping it a secret? Care to share some actual information with us?

    gg

  7. #7
    Join Date
    Nov 2003
    Posts
    1,902

    Re: Turn off the hard disk through WMI

    So you can send ATA commands directly to a drive using IOCTL_ATA_PASS_THROUGH for XP SP2 or higher. Prior to that, you use the undocumented IOCTL_IDE_PASS_THROUGH. This would allow you to spindown a specific drive without affecting other drives.

    There's a Win32 version of the Linux hdparm utility which can spin down an individual drive. You could call this utility directly or try to incorporate its source into your own:
    http://hdparm-win32.dyndns.org/hdparm/

    WMI still isn't an option.

    gg

  8. #8
    Join Date
    Oct 2008
    Posts
    6

    Re: Turn off the hard disk through WMI

    >>The best you can do is change the power policy for when disks should spin-down.

    Thank you.I tried this, and saw that this have the same result as I changed the "turn off disk time" in "control pannel->power option".
    But this still have defect:
    There are two disks in my system,I just want to realize turn off the disk that system Volume not exist in.In this way,two disks sleeped when the system idled for a time setted,and then if I access the system disk,another
    disk get run together[I wanted the other disk sleeped until actualy access it].
    Can I realize this in the way you offered?

  9. #9
    Join Date
    Oct 2008
    Posts
    6

    Re: Turn off the hard disk through WMI

    >>So you can send ATA commands directly to a drive using IOCTL_ATA_PASS_THROUGH for XP SP2 or higher...

    I will try this way, thank you very much..

  10. #10
    Join Date
    Oct 2008
    Posts
    6

    Re: Turn off the hard disk through WMI

    >>So you can send ATA commands directly to a drive using IOCTL_ATA_PASS_THROUGH for XP SP2 or higher...

    ATA/ATAPI-6 Spec specificationSpec shows that SLEEP command can cause the device to enter Sleep
    mode.I try to use it,but encounter problem:
    Call the function "DeviceIoControl" failed,and GetLastError returns error code
    is "122".

    I tried to use IOCTL_ATA_PASS_THROUGH instead of DFP_SEND_DRIVE_CMD,still failed,and GetLastError returns error code
    is "87".
    DFP_SEND_DRIVE_COMMAND is not right?Or SENDCMDINPARAMS,SENDCMDOUTPARAMS
    [these two structure in reference to one SMART program from
    http://smartlinux.sourceforge.net/smart/index.php] is not correct?
    Or others?
    Any advice would be appreciated,thanks.


    code:-----------------------------

    #include "stdafx.h"

    #include <stdio.h>
    #include <conio.h>
    #include <windows.h>
    #include <Ntddscsi.h>
    #include <winioctl.h>


    #define DFP_GET_VERSION 0x00074080
    #define DFP_SEND_DRIVE_COMMAND 0x0007c084
    #define DFP_RECEIVE_DRIVE_DATA 0x0007c088


    typedef struct _IDEREGS {
    BYTE bFeaturesReg; // Used for specifying SMART "commands".
    BYTE bSectorCountReg; // IDE sector count register
    BYTE bSectorNumberReg; // IDE sector number register
    BYTE bCylLowReg; // IDE low order cylinder value
    BYTE bCylHighReg; // IDE high order cylinder value
    BYTE bDriveHeadReg; // IDE drive/head register
    BYTE bCommandReg; // Actual IDE command.
    BYTE bReserved; // reserved for future use. Must be zero.
    } IDEREGS, *PIDEREGS, *LPIDEREGS;

    typedef struct _SENDCMDINPARAMS {
    DWORD cBufferSize; // Buffer size in bytes
    IDEREGS irDriveRegs; // Structure with drive register values.
    BYTE bDriveNumber; // Physical drive number to send
    // command to (0,1,2,3).
    BYTE bReserved[3]; // Reserved for future expansion.
    DWORD dwReserved[4]; // For future use.
    BYTE bBuffer[1]; // Input buffer.
    } SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;

    typedef struct _DRIVERSTATUS {
    BYTE bDriverError;

    BYTE SectorCount;

    BYTE LBALow;
    BYTE LBAMid;
    BYTE LBAHigh;
    BYTE Device;
    BYTE Status;
    } DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;

    typedef struct _SENDCMDOUTPARAMS {
    DWORD cBufferSize; // Size of bBuffer in bytes
    DRIVERSTATUS DriverStatus; // Driver status structure.
    BYTE bBuffer[1]; // Buffer of arbitrary length in which to store
    // the data read from the drive.
    } SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;


    int main()
    {


    HANDLE hSMARTIOCTL = 0;
    if ((hSMARTIOCTL = CreateFile("\\\\.\\PhysicalDrive0",GENERIC_READ | GENERIC_WRITE,
    FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL))
    == INVALID_HANDLE_VALUE)

    {
    printf("Unable to open physical drive, error code: 0x%lX\n",
    GetLastError());
    }
    else
    {
    printf("Physical drive opened successfully\n");
    }

    BOOL fResult;
    DWORD dwError;
    SENDCMDINPARAMS SCIP;
    SENDCMDOUTPARAMS SCOP;
    PDWORD BytesReturned;
    memset((&SCIP), 0, sizeof(SENDCMDINPARAMS));
    memset((&SCOP), 0, sizeof(SENDCMDOUTPARAMS));

    SCIP.cBufferSize = 0;
    SCIP.irDriveRegs.bCommandReg = 0xE6;

    fResult=DeviceIoControl(hSMARTIOCTL, DFP_SEND_DRIVE_COMMAND,
    (LPVOID)(&SCIP), sizeof(SENDCMDINPARAMS) - 1,
    (LPVOID)(&SCOP), sizeof(SENDCMDOUTPARAMS) - 1,
    BytesReturned, NULL) ;

    if (!fResult)
    {
    dwError = GetLastError ();

    printf("dwError=%d\n",dwError);
    }


    return 0;
    }

  11. #11
    Join Date
    Sep 2011
    Posts
    1

    Re: Turn off the hard disk through WMI

    Hi there,

    found this old thread while searching for the same problem. Did you have any success issuing the sleep command?

    Regards,
    Christian.

  12. #12
    Join Date
    May 1999
    Location
    ALABAMA, USA
    Posts
    9,917

    Re: Turn off the hard disk through WMI

    Quote Originally Posted by Zhoucj View Post
    Platform SDK says "Defines the desired power state for a logical device
    and when a device should be put into that state. Not implemented by WMI."
    What is "Not implemented by WMI" mean?......
    It means exactly what it says.
    This method is currently not implemented by WMI. To use this method, you must implement it in your own provider.
    There are only 10 types of people in the world:
    Those who understand binary and those who do not.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured