11#include " pch.h"
22#include " HutaoNativePhysicalDrive.h"
3+ #include " HutaoString.h"
34#include < winioctl.h>
45
56HRESULT __stdcall HutaoNativePhysicalDrive::IsPathOnSolidStateDrive (PCWSTR root, BOOL* isSSD) noexcept
@@ -9,39 +10,36 @@ HRESULT __stdcall HutaoNativePhysicalDrive::IsPathOnSolidStateDrive(PCWSTR root,
910 return E_POINTER;
1011 }
1112
12- // Check if path is empty
1313 if (root[0 ] == L' \0 ' )
1414 {
1515 return E_INVALIDARG;
1616 }
1717
18- // Get drive letter (e.g., "C:\" -> "C:")
19- wchar_t drive[4 ] = { L' C' , L' :' , L' \\ ' , L' \0 ' };
20- if (root[1 ] == L' :' )
18+ wchar_t driveLetter = L' \0 ' ;
19+ size_t len = wcslen (root);
20+
21+ if (len >= 2 && root[1 ] == L' :' )
2122 {
22- drive[ 0 ] = root[0 ];
23+ driveLetter = root[0 ];
2324 }
2425 else
2526 {
26- // If not a valid drive path, return error
2727 return E_INVALIDARG;
2828 }
2929
30- // Create drive path
3130 HutaoString drivePath = L" \\\\ .\\ " ;
32- // 创建一个包含单个字符的字符串
33- wchar_t driveChar[2 ] = { drive[0 ], L' \0 ' };
34- drivePath += driveChar;
31+ wchar_t driveLetterStr[2 ] = { driveLetter, L' \0 ' };
32+ drivePath += driveLetterStr;
3533 drivePath += L" :" ;
3634
37- // Open drive
35+ // Open drive with read access
3836 HANDLE hDrive = CreateFileW (
3937 drivePath.Data (),
40- 0 ,
38+ GENERIC_READ ,
4139 FILE_SHARE_READ | FILE_SHARE_WRITE,
4240 nullptr ,
4341 OPEN_EXISTING,
44- 0 ,
42+ FILE_ATTRIBUTE_NORMAL ,
4543 nullptr
4644 );
4745
@@ -50,7 +48,7 @@ HRESULT __stdcall HutaoNativePhysicalDrive::IsPathOnSolidStateDrive(PCWSTR root,
5048 return HRESULT_FROM_WIN32 (GetLastError ());
5149 }
5250
53- // Get disk properties
51+ // Method 1: Check device type
5452 STORAGE_PROPERTY_QUERY query = {};
5553 query.PropertyId = StorageDeviceProperty;
5654 query.QueryType = PropertyStandardQuery;
@@ -76,11 +74,11 @@ HRESULT __stdcall HutaoNativePhysicalDrive::IsPathOnSolidStateDrive(PCWSTR root,
7674 return HRESULT_FROM_WIN32 (GetLastError ());
7775 }
7876
79- // Allocate buffer large enough
77+ // Allocate buffer
8078 DWORD bufferSize = header.Size ;
8179 if (bufferSize == 0 )
8280 {
83- bufferSize = sizeof (STORAGE_DEVICE_DESCRIPTOR) + 1024 ; // Default size
81+ bufferSize = sizeof (STORAGE_DEVICE_DESCRIPTOR) + 1024 ;
8482 }
8583
8684 BYTE* buffer = new BYTE[bufferSize];
@@ -102,29 +100,88 @@ HRESULT __stdcall HutaoNativePhysicalDrive::IsPathOnSolidStateDrive(PCWSTR root,
102100 nullptr
103101 );
104102
105- CloseHandle (hDrive);
106-
107103 if (!result)
108104 {
109105 delete[] buffer;
106+ CloseHandle (hDrive);
110107 return HRESULT_FROM_WIN32 (GetLastError ());
111108 }
112109
113110 // Parse device descriptor
114111 STORAGE_DEVICE_DESCRIPTOR* descriptor = reinterpret_cast <STORAGE_DEVICE_DESCRIPTOR*>(buffer);
115112
116- // Check media type
117- // SSD is usually DeviceType == 0x0C (SEMICONDUCTOR_DRIVE)
118113 BOOL isSolidState = FALSE ;
119114
120- // Check device type: SSD is usually 0x0C (SEMICONDUCTOR_DRIVE)
121- if (descriptor->DeviceType == 0x0C )
115+ // Check 1: Device type - SSD is usually 0x0C (SEMICONDUCTOR_DRIVE)
116+ // But some SSDs report as 0x00 (unknown) or 0x07 (FILE_DEVICE_DISK)
117+ if (descriptor->DeviceType == 0x0C ) // SEMICONDUCTOR_DRIVE
122118 {
123119 isSolidState = TRUE ;
124120 }
125- // Could also check other flags, but DeviceType is most reliable
121+ else if (descriptor->DeviceType == 0x00 || descriptor->DeviceType == 0x07 )
122+ {
123+ // Could be SSD, need additional checks
124+ // Method 2: Check for seek penalty property
125+ STORAGE_PROPERTY_QUERY seekPenaltyQuery = {};
126+ seekPenaltyQuery.PropertyId = StorageDeviceSeekPenaltyProperty;
127+ seekPenaltyQuery.QueryType = PropertyStandardQuery;
128+
129+ DEVICE_SEEK_PENALTY_DESCRIPTOR seekPenaltyDesc = {};
130+ DWORD seekBytesReturned = 0 ;
131+
132+ result = DeviceIoControl (
133+ hDrive,
134+ IOCTL_STORAGE_QUERY_PROPERTY,
135+ &seekPenaltyQuery,
136+ sizeof (seekPenaltyQuery),
137+ &seekPenaltyDesc,
138+ sizeof (seekPenaltyDesc),
139+ &seekBytesReturned,
140+ nullptr
141+ );
142+
143+ if (result)
144+ {
145+ // SSDs typically have no seek penalty (IncursSeekPenalty = FALSE)
146+ // HDDs typically have seek penalty (IncursSeekPenalty = TRUE)
147+ if (!seekPenaltyDesc.IncursSeekPenalty )
148+ {
149+ isSolidState = TRUE ;
150+ }
151+ }
152+
153+ // Method 3: Check for TRIM support (optional)
154+ if (!isSolidState)
155+ {
156+ STORAGE_PROPERTY_QUERY trimQuery = {};
157+ trimQuery.PropertyId = StorageDeviceTrimProperty;
158+ trimQuery.QueryType = PropertyStandardQuery;
159+
160+ DEVICE_TRIM_DESCRIPTOR trimDesc = {};
161+ DWORD trimBytesReturned = 0 ;
162+
163+ result = DeviceIoControl (
164+ hDrive,
165+ IOCTL_STORAGE_QUERY_PROPERTY,
166+ &trimQuery,
167+ sizeof (trimQuery),
168+ &trimDesc,
169+ sizeof (trimDesc),
170+ &trimBytesReturned,
171+ nullptr
172+ );
173+
174+ if (result && trimDesc.TrimEnabled )
175+ {
176+ // Device supports TRIM, likely an SSD
177+ isSolidState = TRUE ;
178+ }
179+ }
180+ }
126181
127182 delete[] buffer;
183+ CloseHandle (hDrive);
184+
128185 *isSSD = isSolidState;
129186 return S_OK;
130187}
0 commit comments