sbWindowsDeviceUtils.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 :miv */
3 /*
4  *=BEGIN SONGBIRD GPL
5  *
6  * This file is part of the Songbird web player.
7  *
8  * Copyright(c) 2005-2010 POTI, Inc.
9  * http://www.songbirdnest.com
10  *
11  * This file may be licensed under the terms of of the
12  * GNU General Public License Version 2 (the ``GPL'').
13  *
14  * Software distributed under the License is distributed
15  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
16  * express or implied. See the GPL for the specific language
17  * governing rights and limitations.
18  *
19  * You should have received a copy of the GPL along with this
20  * program. If not, go to http://www.gnu.org/licenses/gpl.html
21  * or write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  *=END SONGBIRD GPL
25  */
26 
27 //------------------------------------------------------------------------------
28 //
29 // Songbird Windows device utilities services.
30 //
31 //------------------------------------------------------------------------------
32 
38 //------------------------------------------------------------------------------
39 //
40 // Songbird Windows device utilities imported services.
41 //
42 //------------------------------------------------------------------------------
43 
44 // Self import.
45 #include "sbWindowsDeviceUtils.h"
46 
47 // Songbird imports.
48 #include <sbWindowsUtils.h>
49 
50 // Windows imports.
51 #include <dbt.h>
52 #include <winioctl.h>
53 
54 
55 //------------------------------------------------------------------------------
56 //
57 // Songbird Windows device utilities defs.
58 //
59 //------------------------------------------------------------------------------
60 
61 //
62 // Win32 device GUID defs.
63 //
64 // These are defined here to avoid DDK library dependencies.
65 //
66 
67 static const GUID GUID_DEVINTERFACE_USB_HUB =
68 {
69  0xF18A0E88,
70  0xC30C,
71  0x11D0,
72  { 0x88, 0x15, 0x00, 0xA0, 0xC9, 0x06, 0xBE, 0xD8 }
73 };
74 
75 
76 //------------------------------------------------------------------------------
77 //
78 // Songbird Windows device file services.
79 //
80 //------------------------------------------------------------------------------
81 
101 nsresult
102 sbWinCreateDeviceFile(HANDLE* aDevFile,
103  DEVINST aDevInst,
104  const GUID* aGUID,
105  DWORD aDesiredAccess,
106  DWORD aShareMode,
107  LPSECURITY_ATTRIBUTES aSecurityAttributes,
108  DWORD aCreationDisposition,
109  DWORD aFlagsAndAttributes,
110  HANDLE aTemplateFile)
111 {
112  // Validate arguments.
113  NS_ENSURE_ARG_POINTER(aDevFile);
114  NS_ENSURE_ARG_POINTER(aGUID);
115 
116  // Function variables.
117  nsresult rv;
118 
119  // Get the device path.
120  nsAutoString devicePath;
121  rv = sbWinGetDevicePath(aDevInst, aGUID, devicePath);
122  NS_ENSURE_SUCCESS(rv, rv);
123 
124  // Create the device file.
125  HANDLE devFile = CreateFileW(devicePath.get(),
126  aDesiredAccess,
127  aShareMode,
128  aSecurityAttributes,
129  aCreationDisposition,
130  aFlagsAndAttributes,
131  aTemplateFile);
132  NS_ENSURE_TRUE(devFile != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
133 
134  // Return results.
135  *aDevFile = devFile;
136 
137  return NS_OK;
138 }
139 
140 
161 nsresult
163  DEVINST aDevInst,
164  const GUID* aGUID,
165  DWORD aDesiredAccess,
166  DWORD aShareMode,
167  LPSECURITY_ATTRIBUTES aSecurityAttributes,
168  DWORD aCreationDisposition,
169  DWORD aFlagsAndAttributes,
170  HANDLE aTemplateFile)
171 {
172  // Validate arguments.
173  NS_ENSURE_ARG_POINTER(aDevFile);
174 
175  // Function variables.
176  CONFIGRET cfgRet;
177  nsresult rv;
178 
179  // Search for an ancestor device that has the specified interface.
180  DEVINST ancestorDevInst;
181  DEVINST devInst = aDevInst;
182  while (1) {
183  // Get the next ancestor.
184  cfgRet = CM_Get_Parent(&ancestorDevInst, devInst, 0);
185  if (cfgRet != CR_SUCCESS)
186  return NS_ERROR_NOT_AVAILABLE;
187 
188  // Check if the ancestor has the interface.
189  PRBool hasInterface;
190  rv = sbWinDeviceHasInterface(ancestorDevInst, aGUID, &hasInterface);
191  NS_ENSURE_SUCCESS(rv, rv);
192  if (hasInterface)
193  break;
194 
195  // Check the next ancestor.
196  devInst = ancestorDevInst;
197  }
198 
199  /* Create a device file for the ancestor. */
200  return sbWinCreateDeviceFile(aDevFile,
201  ancestorDevInst,
202  aGUID,
203  aDesiredAccess,
204  aShareMode,
205  aSecurityAttributes,
206  aCreationDisposition,
207  aFlagsAndAttributes,
208  aTemplateFile);
209 }
210 
211 
222 nsresult
223 sbWinDeviceHasInterface(DEVINST aDevInst,
224  const GUID* aGUID,
225  PRBool* aHasInterface)
226 {
227  // Validate arguments.
228  NS_ENSURE_ARG_POINTER(aGUID);
229  NS_ENSURE_ARG_POINTER(aHasInterface);
230 
231  // Function variables.
232  nsresult rv;
233 
234  // Set default result.
235  *aHasInterface = PR_FALSE;
236 
237  // Get the device info set and set it up for auto-disposal.
238  nsAutoString deviceInstanceID;
239  rv = sbWinGetDeviceInstanceID(aDevInst, deviceInstanceID);
240  NS_ENSURE_SUCCESS(rv, rv);
241  HDEVINFO devInfo = SetupDiGetClassDevsW(aGUID,
242  deviceInstanceID.get(),
243  NULL,
244  DIGCF_DEVICEINTERFACE);
245  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
246  sbAutoHDEVINFO autoDevInfo(devInfo);
247 
248  // Get the device info for the device instance. Device does not have the
249  // interface if it does not have a device info data record.
250  SP_DEVINFO_DATA devInfoData;
251  rv = sbWinGetDevInfoData(aDevInst, devInfo, &devInfoData);
252  if (NS_FAILED(rv))
253  return NS_OK;
254 
255  // Get the device interface detail. Device does not have the interface if it
256  // does not have the interface detail.
257  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
258  rv = sbWinGetDevInterfaceDetail(&devIfDetailData,
259  devInfo,
260  &devInfoData,
261  aGUID);
262  if (NS_FAILED(rv))
263  return NS_OK;
264  sbAutoNSMemPtr autoDevIfDetailData(devIfDetailData);
265 
266  // Device has the interface.
267  *aHasInterface = PR_TRUE;
268 
269  return NS_OK;
270 }
271 
272 
282 nsresult
283 sbWinGetDevicePath(DEVINST aDevInst,
284  const GUID* aGUID,
285  nsAString& aDevicePath)
286 {
287  // Validate arguments.
288  NS_ENSURE_ARG_POINTER(aGUID);
289 
290  // Function variables.
291  nsresult rv;
292 
293  // Get the device info set and set it up for auto-disposal.
294  nsAutoString deviceInstanceID;
295  rv = sbWinGetDeviceInstanceID(aDevInst, deviceInstanceID);
296  NS_ENSURE_SUCCESS(rv, rv);
297  HDEVINFO devInfo = SetupDiGetClassDevsW(aGUID,
298  deviceInstanceID.get(),
299  NULL,
300  DIGCF_DEVICEINTERFACE);
301  NS_ENSURE_TRUE(devInfo != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
302  sbAutoHDEVINFO autoDevInfo(devInfo);
303 
304  // Get the device info for the device instance.
305  SP_DEVINFO_DATA devInfoData;
306  rv = sbWinGetDevInfoData(aDevInst, devInfo, &devInfoData);
307  NS_ENSURE_SUCCESS(rv, rv);
308 
309  // Get the device interface detail data for the device instance.
310  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
311  rv = sbWinGetDevInterfaceDetail(&devIfDetailData,
312  devInfo,
313  &devInfoData,
314  aGUID);
315  NS_ENSURE_SUCCESS(rv, rv);
316  sbAutoNSMemPtr autoDevIfDetailData(devIfDetailData);
317 
318  // Return results.
319  aDevicePath.Assign(devIfDetailData->DevicePath);
320 
321  return NS_OK;
322 }
323 
324 
325 //------------------------------------------------------------------------------
326 //
327 // Songbird Windows device utilities services.
328 //
329 //------------------------------------------------------------------------------
330 
346 static nsresult _sbWinFindDevicesByInterface
347  (nsTArray<DEVINST>& aDevInstList,
348  DEVINST aRootDevInst,
349  const GUID* aGUID,
350  PRBool aSearchAncestors);
351 
352 nsresult
353 sbWinFindDevicesByInterface(nsTArray<DEVINST>& aDevInstList,
354  DEVINST aRootDevInst,
355  const GUID* aGUID,
356  PRBool aSearchAncestors)
357 {
358  // Clear device instance list.
359  aDevInstList.Clear();
360 
361  return _sbWinFindDevicesByInterface(aDevInstList,
362  aRootDevInst,
363  aGUID,
364  aSearchAncestors);
365 }
366 
367 nsresult
368 _sbWinFindDevicesByInterface(nsTArray<DEVINST>& aDevInstList,
369  DEVINST aRootDevInst,
370  const GUID* aGUID,
371  PRBool aSearchAncestors)
372 {
373  // Validate arguments.
374  NS_ENSURE_ARG_POINTER(aGUID);
375 
376  // Function variables.
377  CONFIGRET cr;
378  nsresult rv;
379 
380  // Check if the root device has the specified interface.
381  PRBool hasInterface;
382  rv = sbWinDeviceHasInterface(aRootDevInst, aGUID, &hasInterface);
383  NS_ENSURE_SUCCESS(rv, rv);
384  if (hasInterface) {
385  NS_ENSURE_TRUE(aDevInstList.AppendElement(aRootDevInst),
386  NS_ERROR_OUT_OF_MEMORY);
387  }
388 
389  // Search all descendents or ancestors of device.
390  if (aSearchAncestors) {
391  DEVINST parentDevInst;
392  cr = CM_Get_Parent(&parentDevInst, aRootDevInst, 0);
393  if (cr == CR_SUCCESS) {
394  // Search parent.
395  rv = _sbWinFindDevicesByInterface(aDevInstList,
396  parentDevInst,
397  aGUID,
398  aSearchAncestors);
399  NS_ENSURE_SUCCESS(rv, rv);
400  }
401  } else {
402  DEVINST childDevInst;
403  cr = CM_Get_Child(&childDevInst, aRootDevInst, 0);
404  while (cr == CR_SUCCESS) {
405  // Search child.
406  rv = _sbWinFindDevicesByInterface(aDevInstList,
407  childDevInst,
408  aGUID,
409  aSearchAncestors);
410  NS_ENSURE_SUCCESS(rv, rv);
411 
412  // Get the next child. An error indicates that no more children are
413  // present.
414  cr = CM_Get_Sibling(&childDevInst, childDevInst, 0);
415  }
416  }
417 
418  return NS_OK;
419 }
420 
421 
433 nsresult
434 sbWinFindDeviceByClass(DEVINST* aDevInst,
435  PRBool* aFound,
436  DEVINST aRootDevInst,
437  const nsAString& aClass)
438 {
439  // Validate arguments.
440  NS_ENSURE_ARG_POINTER(aDevInst);
441  NS_ENSURE_ARG_POINTER(aFound);
442 
443  // Function variables.
444  PRBool found = PR_FALSE;
445  CONFIGRET cr;
446  nsresult rv;
447 
448  // Get the root device class.
449  WCHAR propBuffer[256];
450  ULONG length = sizeof(propBuffer);
451  cr = CM_Get_DevNode_Registry_PropertyW(aRootDevInst,
452  CM_DRP_CLASS,
453  NULL,
454  propBuffer,
455  &length,
456  0);
457  NS_ENSURE_TRUE(cr == CR_SUCCESS, NS_ERROR_FAILURE);
458 
459  // Check if the root device class matches. If it does, return.
460  nsDependentString property(propBuffer);
461  if (property.Equals(aClass)) {
462  *aDevInst = aRootDevInst;
463  *aFound = PR_TRUE;
464  return NS_OK;
465  }
466 
467  // Search all descendents of device.
468  DEVINST childDevInst;
469  cr = CM_Get_Child(&childDevInst, aRootDevInst, 0);
470  while (cr == CR_SUCCESS) {
471  // Search child.
472  rv = sbWinFindDeviceByClass(aDevInst, &found, childDevInst, aClass);
473  NS_ENSURE_SUCCESS(rv, rv);
474  if (found) {
475  found = PR_TRUE;
476  break;
477  }
478 
479  // Get the next child. An error indicates that no more children are
480  // present.
481  cr = CM_Get_Sibling(&childDevInst, childDevInst, 0);
482  }
483 
484  // Return results.
485  *aFound = found;
486 
487  return NS_OK;
488 }
489 
490 
503 nsresult
504 sbWinGetDevInfoData(DEVINST aDevInst,
505  HDEVINFO aDevInfo,
506  PSP_DEVINFO_DATA aDevInfoData)
507 {
508  // Validate arguments.
509  NS_ENSURE_ARG_POINTER(aDevInfoData);
510 
511  // Function variables.
512  BOOL success;
513 
514  // Find the device info data for the device instance.
515  DWORD devIndex = 0;
516  while (1) {
517  // Get the next device info data.
518  aDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
519  success = SetupDiEnumDeviceInfo(aDevInfo, devIndex, aDevInfoData);
520  if (!success)
521  return NS_ERROR_NOT_AVAILABLE;
522 
523  // The search is done if the device info data is for the device instance.
524  if (aDevInfoData->DevInst == aDevInst)
525  break;
526 
527  // Check the next device info data.
528  devIndex++;
529  }
530 
531  return NS_OK;
532 }
533 
534 
548 nsresult
549 sbWinGetDevDetail(PSP_DEVICE_INTERFACE_DETAIL_DATA* aDevIfDetailData,
550  SP_DEVINFO_DATA* aDevInfoData,
551  HDEVINFO aDevInfo,
552  const GUID* aGUID,
553  DWORD aDevIndex)
554 {
555  // Validate arguments.
556  NS_ENSURE_ARG_POINTER(aDevIfDetailData);
557  NS_ENSURE_ARG_POINTER(aDevInfoData);
558  NS_ENSURE_ARG_POINTER(aGUID);
559 
560  // Function variables.
561  BOOL success;
562 
563  // Set up to get the device interface detail data. If not successful, there's
564  // no more device interfaces to enumerate.
565  SP_DEVICE_INTERFACE_DATA devIfData;
566  ZeroMemory(&devIfData, sizeof(SP_DEVICE_INTERFACE_DATA));
567  devIfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
568  success = SetupDiEnumDeviceInterfaces(aDevInfo,
569  NULL,
570  aGUID,
571  aDevIndex,
572  &devIfData);
573  if (!success)
574  return NS_ERROR_NOT_AVAILABLE;
575 
576  // Get the required size of the device interface detail data.
577  DWORD size = 0;
578  success = SetupDiGetDeviceInterfaceDetailW(aDevInfo,
579  &devIfData,
580  NULL,
581  0,
582  &size,
583  NULL);
584  NS_ENSURE_TRUE(size > 0, NS_ERROR_FAILURE);
585 
586  // Allocate the device interface detail data record and set it up for
587  // auto-disposal.
588  PSP_DEVICE_INTERFACE_DETAIL_DATA
589  devIfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(size);
590  NS_ENSURE_TRUE(devIfDetailData, NS_ERROR_OUT_OF_MEMORY);
592  autoDevIfDetailData(devIfDetailData);
593  devIfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
594 
595  // Get the device interface details.
596  ZeroMemory(aDevInfoData, sizeof(SP_DEVINFO_DATA));
597  aDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
598  success = SetupDiGetDeviceInterfaceDetailW(aDevInfo,
599  &devIfData,
600  devIfDetailData,
601  size,
602  NULL,
603  aDevInfoData);
604  NS_ENSURE_SUCCESS(success, NS_ERROR_FAILURE);
605 
606  // Return results.
607  *aDevIfDetailData =
608  (PSP_DEVICE_INTERFACE_DETAIL_DATA) autoDevIfDetailData.forget();
609 
610  return NS_OK;
611 }
612 
613 
633 nsresult
634 sbWinGetDevInterfaceDetail(PSP_DEVICE_INTERFACE_DETAIL_DATA* aDevIfDetailData,
635  HDEVINFO aDevInfo,
636  SP_DEVINFO_DATA* aDevInfoData,
637  const GUID* aGUID)
638 {
639  // Validate arguments.
640  NS_ENSURE_ARG_POINTER(aDevIfDetailData);
641  NS_ENSURE_ARG_POINTER(aDevInfoData);
642  NS_ENSURE_ARG_POINTER(aGUID);
643 
644  // Function variables.
645  BOOL success;
646 
647  // Get the device interface data for the requested device and interface GUID.
648  SP_DEVICE_INTERFACE_DATA devIfData;
649  ZeroMemory(&devIfData, sizeof(SP_DEVICE_INTERFACE_DATA));
650  devIfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
651  success = SetupDiEnumDeviceInterfaces(aDevInfo,
652  aDevInfoData,
653  aGUID,
654  0,
655  &devIfData);
656  if (!success)
657  return NS_ERROR_NOT_AVAILABLE;
658 
659  // Get the required size of the device interface detail data.
660  DWORD size = 0;
661  success = SetupDiGetDeviceInterfaceDetailW(aDevInfo,
662  &devIfData,
663  NULL,
664  0,
665  &size,
666  NULL);
667  if (!success) {
668  NS_ENSURE_TRUE(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
669  NS_ERROR_FAILURE);
670  }
671  NS_ENSURE_TRUE(size > 0, NS_ERROR_FAILURE);
672 
673  // Allocate the device interface detail data record and set it up for
674  // auto-disposal.
675  PSP_DEVICE_INTERFACE_DETAIL_DATA devIfDetailData;
676  devIfDetailData =
677  static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(NS_Alloc(size));
678  NS_ENSURE_TRUE(devIfDetailData, NS_ERROR_OUT_OF_MEMORY);
679  sbAutoNSMemPtr autoDevIfDetailData(devIfDetailData);
680 
681  // Get the device interface details.
682  devIfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
683  success = SetupDiGetDeviceInterfaceDetailW(aDevInfo,
684  &devIfData,
685  devIfDetailData,
686  size,
687  NULL,
688  NULL);
689  NS_ENSURE_SUCCESS(success, NS_ERROR_FAILURE);
690 
691  // Return results.
692  *aDevIfDetailData =
693  static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(autoDevIfDetailData.forget());
694 
695  return NS_OK;
696 }
697 
698 
707 nsresult
708 sbWinGetDeviceInstanceIDFromDeviceInterfaceName(nsAString& aDeviceInterfaceName,
709  nsAString& aDeviceInstanceID)
710 {
711  BOOL success;
712  nsresult rv;
713 
714  // Create a device info set and set it up for auto-disposal.
715  HDEVINFO devInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);
716  NS_ENSURE_TRUE(devInfoSet != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
717  sbAutoHDEVINFO autoDevInfoSet(devInfoSet);
718 
719  // Add the device interface data, including the device info data, to the
720  // device info set.
721  SP_DEVICE_INTERFACE_DATA devIfData;
722  ZeroMemory(&devIfData, sizeof(SP_DEVICE_INTERFACE_DATA));
723  devIfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
724  success = SetupDiOpenDeviceInterfaceW(devInfoSet,
725  aDeviceInterfaceName.BeginReading(),
726  0,
727  &devIfData);
728  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
729 
730  // Get the device info data.
731  SP_DEVINFO_DATA devInfoData;
732  devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
733  success = SetupDiEnumDeviceInfo(devInfoSet, 0, &devInfoData);
734  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
735 
736  // Get the device instance ID.
737  rv = sbWinGetDeviceInstanceID(devInfoData.DevInst, aDeviceInstanceID);
738  NS_ENSURE_SUCCESS(rv, rv);
739 
740  return NS_OK;
741 }
742 
743 
752 nsresult
753 sbWinGetDeviceInstanceID(DEVINST aDevInst,
754  nsAString& aDeviceInstanceID)
755 {
756  CONFIGRET cr;
757 
758  // Get the device instance ID.
759  TCHAR deviceInstanceID[MAX_DEVICE_ID_LEN];
760  cr = CM_Get_Device_ID(aDevInst, deviceInstanceID, MAX_DEVICE_ID_LEN, 0);
761  NS_ENSURE_TRUE(cr == CR_SUCCESS, NS_ERROR_FAILURE);
762  aDeviceInstanceID.Assign(deviceInstanceID);
763 
764  return NS_OK;
765 }
766 
767 
774 nsresult
775 sbWinDeviceEject(DEVINST aDevInst)
776 {
777  CONFIGRET cfgRet;
778 
779  // Try ejecting the device three times.
780  WCHAR vetoName[MAX_PATH];
781  PNP_VETO_TYPE vetoType;
782  PRBool ejected = PR_FALSE;
783  for (int i = 0; i < 3; i++) {
784  // Try ejecting using CM_Request_Device_Eject.
785  cfgRet = CM_Request_Device_EjectW(aDevInst,
786  &vetoType,
787  vetoName,
788  MAX_PATH,
789  0);
790  if (cfgRet == CR_SUCCESS) {
791  ejected = PR_TRUE;
792  break;
793  }
794  // Wait for 1/10 second to give the device time to handle the eject.
795  // This probably isn't needed, but all the examples I saw that used
796  // the functions always put in a delay between calls at least for retries
797  Sleep(100);
798  // Try ejecting using CM_Query_And_Remove_SubTree.
799  cfgRet = CM_Query_And_Remove_SubTreeW(aDevInst,
800  &vetoType,
801  vetoName,
802  MAX_PATH,
803  CM_REMOVE_NO_RESTART);
804  if (cfgRet == CR_SUCCESS) {
805  ejected = PR_TRUE;
806  break;
807  }
808  // Wait 1/2 before retrying so we don't just slam the device with a bunch
809  // of eject/remove requests and fail out.
810  Sleep(500);
811  }
812 
813  // Try one last time and let the PnP manager notify the user of failure.
814  if (!ejected) {
815  cfgRet = CM_Request_Device_Eject(aDevInst, NULL, NULL, 0, 0);
816  NS_ENSURE_TRUE(cfgRet == CR_SUCCESS, NS_ERROR_FAILURE);
817  }
818 
819  return NS_OK;
820 }
821 
826 nsresult
827 sbWinDeviceEject(nsAString const & aMountPath)
828 {
829 
830  DWORD byteCount;
831  BOOL success;
832 
833  nsString volumePath(NS_LITERAL_STRING("\\\\.\\"));
834  volumePath.Append(aMountPath);
835  volumePath.Trim("\\", PR_FALSE, PR_TRUE);
836 
837  // Create a disk interface device file.
838  sbAutoHANDLE diskHandle = CreateFileW(volumePath.BeginReading(),
839  GENERIC_READ | GENERIC_WRITE,
840  FILE_SHARE_READ | FILE_SHARE_WRITE,
841  NULL,
842  OPEN_EXISTING,
843  0,
844  NULL);
845  NS_ENSURE_TRUE(diskHandle.get() != INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
846 
847  const PRUint32 LOCK_RETRY = 3;
848  const PRUint32 LOCK_RETRY_WAIT= 500; // Wait between retry in milliseconds
849 
850  for (PRUint32 retry = 0; retry < LOCK_RETRY; ++retry) {
851  success = DeviceIoControl(diskHandle,
852  FSCTL_LOCK_VOLUME,
853  NULL, 0,
854  NULL, 0,
855  &byteCount,
856  NULL);
857  if (success) {
858  break;
859  }
860 #ifdef DEBUG
861  // If this was the last retry then report the error
862  if (!success && retry == LOCK_RETRY - 1) {
863  const DWORD error = GetLastError();
864  printf("FSTL_LOCK_VOLUME failed on %s with code %u\n",
865  NS_LossyConvertUTF16toASCII(volumePath).get(),
866  error);
867  }
868 #endif
869  Sleep(LOCK_RETRY_WAIT);
870  }
871  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
872 
873  success = DeviceIoControl(diskHandle,
874  FSCTL_DISMOUNT_VOLUME,
875  NULL, 0,
876  NULL, 0,
877  &byteCount,
878  NULL);
879  if (!success) {
880 #ifdef DEBUG
881  const DWORD error = GetLastError();
882  printf("FSCTL_DISMOUNT_VOLUME failed on %s with code %u\n",
883  NS_LossyConvertUTF16toASCII(volumePath).get(),
884  error);
885 #endif
886  }
887  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
888 
889  PREVENT_MEDIA_REMOVAL preventMediaRemoval;
890 
891  preventMediaRemoval.PreventMediaRemoval = FALSE;
892 
893  success = DeviceIoControl(diskHandle,
894  IOCTL_STORAGE_MEDIA_REMOVAL,
895  &preventMediaRemoval, sizeof(preventMediaRemoval),
896  NULL, 0,
897  &byteCount,
898  NULL);
899  if (!success) {
900 #ifdef DEBUG
901  const DWORD error = GetLastError();
902  printf("IOCTL_STORAGE_MEDIA_REMOVAL failed on %s with code %u\n",
903  NS_LossyConvertUTF16toASCII(volumePath).get(),
904  error);
905 #endif
906  }
907  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
908 
909  success = DeviceIoControl(diskHandle,
910  IOCTL_STORAGE_EJECT_MEDIA,
911  NULL,
912  0,
913  NULL,
914  0,
915  &byteCount,
916  NULL);
917  if (!success) {
918 #ifdef DEBUG
919  const DWORD error = GetLastError();
920  printf("IOCTL_STORAGE_EJECT_MEDIA failed on %s with code %u\n",
921  NS_LossyConvertUTF16toASCII(volumePath).get(),
922  error);
923 #endif
924  return NS_ERROR_FAILURE;
925  }
926 
927  return NS_OK;
928 }
929 
940 nsresult
941 sbWinDeviceIsDescendantOf(DEVINST aDevInst,
942  DEVINST aDescendantDevInst,
943  PRBool* aIsDescendant)
944 {
945  // Validate arguments.
946  NS_ENSURE_ARG_POINTER(aIsDescendant);
947 
948  // Function variables.
949  PRBool isDescendant = PR_FALSE;
950  CONFIGRET cfgRet;
951 
952  // Search ancestors for target device.
953  DEVINST currentAncestor = aDescendantDevInst;
954  while (1) {
955  // Get the next ancestor.
956  cfgRet = CM_Get_Parent(&currentAncestor, currentAncestor, 0);
957  if (cfgRet != CR_SUCCESS)
958  break;
959 
960  // Check for a match.
961  if (currentAncestor == aDevInst) {
962  isDescendant = PR_TRUE;
963  break;
964  }
965  }
966 
967  // Return results.
968  *aIsDescendant = isDescendant;
969 
970  return NS_OK;
971 }
972 
973 
987 nsresult
988 sbWinRegisterDeviceHandleNotification(HDEVNOTIFY* aDeviceNotification,
989  HWND aEventWindow,
990  DEVINST aDevInst,
991  const GUID& aGUID)
992 {
993  // Validate arguments.
994  NS_ENSURE_ARG_POINTER(aDeviceNotification);
995 
996  // Function variables.
997  nsresult rv;
998 
999  // Create a device file for notifications.
1000  sbAutoHANDLE deviceHandle;
1001  rv = sbWinCreateDeviceFile(deviceHandle.StartAssignment(),
1002  aDevInst,
1003  &aGUID,
1004  0,
1005  FILE_SHARE_READ | FILE_SHARE_WRITE,
1006  NULL,
1007  OPEN_EXISTING,
1008  0,
1009  NULL);
1010  NS_ENSURE_SUCCESS(rv, rv);
1011 
1012  // Register for device handle notifications. The handle may be closed after
1013  // registration without affecting the registration. Doing so avoids having
1014  // extra device file handles open.
1015  HDEVNOTIFY deviceNotification;
1016  DEV_BROADCAST_HANDLE devBroadcast = {0};
1017  devBroadcast.dbch_size = sizeof(devBroadcast);
1018  devBroadcast.dbch_devicetype = DBT_DEVTYP_HANDLE;
1019  devBroadcast.dbch_handle = deviceHandle;
1020  deviceNotification = RegisterDeviceNotification(aEventWindow,
1021  &devBroadcast,
1022  0);
1023  NS_ENSURE_TRUE(deviceNotification, NS_ERROR_FAILURE);
1024 
1025  // Return results.
1026  *aDeviceNotification = deviceNotification;
1027 
1028  return NS_OK;
1029 }
1030 
nsresult sbWinCreateDeviceFile(HANDLE *aDevFile, DEVINST aDevInst, const GUID *aGUID, DWORD aDesiredAccess, DWORD aShareMode, LPSECURITY_ATTRIBUTES aSecurityAttributes, DWORD aCreationDisposition, DWORD aFlagsAndAttributes, HANDLE aTemplateFile)
return NS_OK
nsresult sbWinGetDeviceInstanceID(DEVINST aDevInst, nsAString &aDeviceInstanceID)
static const GUID GUID_DEVINTERFACE_USB_HUB
Songbird Windows Device Utilities Definitions.
static nsresult _sbWinFindDevicesByInterface(nsTArray< DEVINST > &aDevInstList, DEVINST aRootDevInst, const GUID *aGUID, PRBool aSearchAncestors)
nsresult sbWinGetDevInfoData(DEVINST aDevInst, HDEVINFO aDevInfo, PSP_DEVINFO_DATA aDevInfoData)
nsresult sbWinGetDevDetail(PSP_DEVICE_INTERFACE_DETAIL_DATA *aDevIfDetailData, SP_DEVINFO_DATA *aDevInfoData, HDEVINFO aDevInfo, const GUID *aGUID, DWORD aDevIndex)
nsresult sbWinCreateAncestorDeviceFile(HANDLE *aDevFile, DEVINST aDevInst, const GUID *aGUID, DWORD aDesiredAccess, DWORD aShareMode, LPSECURITY_ATTRIBUTES aSecurityAttributes, DWORD aCreationDisposition, DWORD aFlagsAndAttributes, HANDLE aTemplateFile)
nsresult sbWinFindDevicesByInterface(nsTArray< DEVINST > &aDevInstList, DEVINST aRootDevInst, const GUID *aGUID, PRBool aSearchAncestors)
nsresult sbWinFindDeviceByClass(DEVINST *aDevInst, PRBool *aFound, DEVINST aRootDevInst, const nsAString &aClass)
nsresult sbWinDeviceIsDescendantOf(DEVINST aDevInst, DEVINST aDescendantDevInst, PRBool *aIsDescendant)
nsresult sbWinDeviceEject(DEVINST aDevInst)
nsresult sbWinRegisterDeviceHandleNotification(HDEVNOTIFY *aDeviceNotification, HWND aEventWindow, DEVINST aDevInst, const GUID &aGUID)
nsresult sbWinGetDevicePath(DEVINST aDevInst, const GUID *aGUID, nsAString &aDevicePath)
var cr
nsresult sbWinGetDeviceInstanceIDFromDeviceInterfaceName(nsAString &aDeviceInterfaceName, nsAString &aDeviceInstanceID)
nsresult sbWinDeviceHasInterface(DEVINST aDevInst, const GUID *aGUID, PRBool *aHasInterface)
_getSelectedPageStyle s i
nsresult sbWinGetDevInterfaceDetail(PSP_DEVICE_INTERFACE_DETAIL_DATA *aDevIfDetailData, HDEVINFO aDevInfo, SP_DEVINFO_DATA *aDevInfoData, const GUID *aGUID)