VirtualBox

source: vbox/trunk/src/VBox/Devices/Storage/DrvHostBase-win.cpp@ 74441

Last change on this file since 74441 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.3 KB
Line 
1/* $Id: DrvHostBase-win.cpp 73097 2018-07-12 21:06:33Z vboxsync $ */
2/** @file
3 * DrvHostBase - Host base drive access driver, Windows specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_DRV_HOST_BASE
18#pragma warning(disable : 4163)
19#define _interlockedbittestandset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset
20#define _interlockedbittestandreset they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset
21#define _interlockedbittestandset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandset64
22#define _interlockedbittestandreset64 they_messed_it_up_in_winnt_h_this_time_sigh__interlockedbittestandreset64
23
24#define WIN32_NO_STATUS
25#include <iprt/win/windows.h>
26#include <dbt.h>
27#undef WIN32_NO_STATUS
28
29#include <winioctl.h>
30#include <ntddscsi.h>
31#pragma warning(default : 4163)
32#undef _interlockedbittestandset
33#undef _interlockedbittestandreset
34#undef _interlockedbittestandset64
35#undef _interlockedbittestandreset64
36#include <ntstatus.h>
37
38/* from ntdef.h */
39typedef LONG NTSTATUS;
40
41/* from ntddk.h */
42typedef struct _IO_STATUS_BLOCK {
43 union {
44 NTSTATUS Status;
45 PVOID Pointer;
46 };
47 ULONG_PTR Information;
48} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
49
50
51/* from ntinternals.com */
52typedef enum _FS_INFORMATION_CLASS {
53 FileFsVolumeInformation=1,
54 FileFsLabelInformation,
55 FileFsSizeInformation,
56 FileFsDeviceInformation,
57 FileFsAttributeInformation,
58 FileFsControlInformation,
59 FileFsFullSizeInformation,
60 FileFsObjectIdInformation,
61 FileFsMaximumInformation
62} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
63
64typedef struct _FILE_FS_SIZE_INFORMATION {
65 LARGE_INTEGER TotalAllocationUnits;
66 LARGE_INTEGER AvailableAllocationUnits;
67 ULONG SectorsPerAllocationUnit;
68 ULONG BytesPerSector;
69} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
70
71extern "C"
72NTSTATUS __stdcall NtQueryVolumeInformationFile(
73 /*IN*/ HANDLE FileHandle,
74 /*OUT*/ PIO_STATUS_BLOCK IoStatusBlock,
75 /*OUT*/ PVOID FileSystemInformation,
76 /*IN*/ ULONG Length,
77 /*IN*/ FS_INFORMATION_CLASS FileSystemInformationClass );
78
79#include <iprt/ctype.h>
80#include <iprt/file.h>
81#include <VBox/scsi.h>
82
83/** Maximum buffer size we support, check whether darwin has some real upper limit. */
84#define WIN_SCSI_MAX_BUFFER_SIZE (100 * _1K)
85
86/**
87 * Host backend specific data.
88 */
89typedef struct DRVHOSTBASEOS
90{
91 /** The filehandle of the device. */
92 RTFILE hFileDevice;
93 /** Handle to the window we use to catch the device change broadcast messages. */
94 volatile HWND hwndDeviceChange;
95 /** The unit mask. */
96 DWORD fUnitMask;
97 /** Handle of the poller thread. */
98 RTTHREAD hThrdMediaChange;
99} DRVHOSTBASEOS;
100/** Pointer to the host backend specific data. */
101typedef DRVHOSTBASEOS *PDRVHOSBASEOS;
102AssertCompile(sizeof(DRVHOSTBASEOS) <= 64);
103
104#define DRVHOSTBASE_OS_INT_DECLARED
105#include "DrvHostBase.h"
106
107
108/**
109 * Window procedure for the invisible window used to catch the WM_DEVICECHANGE broadcasts.
110 */
111static LRESULT CALLBACK DeviceChangeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
112{
113 Log2(("DeviceChangeWindowProc: hwnd=%08x uMsg=%08x\n", hwnd, uMsg));
114 if (uMsg == WM_DESTROY)
115 {
116 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
117 if (pThis)
118 ASMAtomicXchgSize(&pThis->Os.hwndDeviceChange, NULL);
119 PostQuitMessage(0);
120 }
121
122 if (uMsg != WM_DEVICECHANGE)
123 return DefWindowProc(hwnd, uMsg, wParam, lParam);
124
125 PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
126 PDRVHOSTBASE pThis = (PDRVHOSTBASE)GetWindowLongPtr(hwnd, GWLP_USERDATA);
127 Assert(pThis);
128 if (pThis == NULL)
129 return 0;
130
131 switch (wParam)
132 {
133 case DBT_DEVICEARRIVAL:
134 case DBT_DEVICEREMOVECOMPLETE:
135 // Check whether a CD or DVD was inserted into or removed from a drive.
136 if (lpdb->dbch_devicetype == DBT_DEVTYP_VOLUME)
137 {
138 PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
139 if ( (lpdbv->dbcv_flags & DBTF_MEDIA)
140 && (pThis->Os.fUnitMask & lpdbv->dbcv_unitmask))
141 {
142 RTCritSectEnter(&pThis->CritSect);
143 if (wParam == DBT_DEVICEARRIVAL)
144 {
145 int cRetries = 10;
146 int rc = DRVHostBaseMediaPresent(pThis);
147 while (RT_FAILURE(rc) && cRetries-- > 0)
148 {
149 RTThreadSleep(50);
150 rc = DRVHostBaseMediaPresent(pThis);
151 }
152 }
153 else
154 DRVHostBaseMediaNotPresent(pThis);
155 RTCritSectLeave(&pThis->CritSect);
156 }
157 }
158 break;
159 }
160 return TRUE;
161}
162
163
164/**
165 * This thread will wait for changed media notificatons.
166 *
167 * @returns Ignored.
168 * @param ThreadSelf Handle of this thread. Ignored.
169 * @param pvUser Pointer to the driver instance structure.
170 */
171static DECLCALLBACK(int) drvHostBaseMediaThreadWin(RTTHREAD ThreadSelf, void *pvUser)
172{
173 PDRVHOSTBASE pThis = (PDRVHOSTBASE)pvUser;
174 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: ThreadSelf=%p pvUser=%p\n",
175 pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, ThreadSelf, pvUser));
176 static WNDCLASS s_classDeviceChange = {0};
177 static ATOM s_hAtomDeviceChange = 0;
178
179 /*
180 * Register custom window class.
181 */
182 if (s_hAtomDeviceChange == 0)
183 {
184 memset(&s_classDeviceChange, 0, sizeof(s_classDeviceChange));
185 s_classDeviceChange.lpfnWndProc = DeviceChangeWindowProc;
186 s_classDeviceChange.lpszClassName = "VBOX_DeviceChangeClass";
187 s_classDeviceChange.hInstance = GetModuleHandle("VBoxDD.dll");
188 Assert(s_classDeviceChange.hInstance);
189 s_hAtomDeviceChange = RegisterClassA(&s_classDeviceChange);
190 Assert(s_hAtomDeviceChange);
191 }
192
193 /*
194 * Create Window w/ the pThis as user data.
195 */
196 HWND hwnd = CreateWindow((LPCTSTR)s_hAtomDeviceChange, "", WS_POPUP, 0, 0, 0, 0, 0, 0, s_classDeviceChange.hInstance, 0);
197 AssertMsg(hwnd, ("CreateWindow failed with %d\n", GetLastError()));
198 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
199
200 /*
201 * Signal the waiting EMT thread that everything went fine.
202 */
203 ASMAtomicXchgPtr((void * volatile *)&pThis->Os.hwndDeviceChange, hwnd);
204 RTThreadUserSignal(ThreadSelf);
205 if (!hwnd)
206 {
207 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VERR_GENERAL_FAILURE\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
208 return VERR_GENERAL_FAILURE;
209 }
210 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: Created hwndDeviceChange=%p\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance, hwnd));
211
212 /*
213 * Message pump.
214 */
215 MSG Msg;
216 BOOL fRet;
217 while ((fRet = GetMessage(&Msg, NULL, 0, 0)) != FALSE)
218 {
219 if (fRet != -1)
220 {
221 TranslateMessage(&Msg);
222 DispatchMessage(&Msg);
223 }
224 //else: handle the error and possibly exit
225 }
226 Assert(!pThis->Os.hwndDeviceChange);
227 /* (Don't clear the thread handle here, the destructor thread is using it to wait.) */
228 LogFlow(("%s-%d: drvHostBaseMediaThreadWin: returns VINF_SUCCESS\n", pThis->pDrvIns->pReg->szName, pThis->pDrvIns->iInstance));
229 return VINF_SUCCESS;
230}
231
232
233DECLHIDDEN(int) drvHostBaseScsiCmdOs(PDRVHOSTBASE pThis, const uint8_t *pbCmd, size_t cbCmd, PDMMEDIATXDIR enmTxDir,
234 void *pvBuf, uint32_t *pcbBuf, uint8_t *pbSense, size_t cbSense, uint32_t cTimeoutMillies)
235{
236 /*
237 * Minimal input validation.
238 */
239 Assert(enmTxDir == PDMMEDIATXDIR_NONE || enmTxDir == PDMMEDIATXDIR_FROM_DEVICE || enmTxDir == PDMMEDIATXDIR_TO_DEVICE);
240 Assert(!pvBuf || pcbBuf);
241 Assert(pvBuf || enmTxDir == PDMMEDIATXDIR_NONE);
242 Assert(pbSense || !cbSense);
243 AssertPtr(pbCmd);
244 Assert(cbCmd <= 16 && cbCmd >= 1); RT_NOREF(cbCmd);
245
246 int rc = VERR_GENERAL_FAILURE;
247 int direction;
248 struct _REQ
249 {
250 SCSI_PASS_THROUGH_DIRECT spt;
251 uint8_t aSense[64];
252 } Req;
253 DWORD cbReturned = 0;
254
255 switch (enmTxDir)
256 {
257 case PDMMEDIATXDIR_NONE:
258 direction = SCSI_IOCTL_DATA_UNSPECIFIED;
259 break;
260 case PDMMEDIATXDIR_FROM_DEVICE:
261 Assert(*pcbBuf != 0);
262 /* Make sure that the buffer is clear for commands reading
263 * data. The actually received data may be shorter than what
264 * we expect, and due to the unreliable feedback about how much
265 * data the ioctl actually transferred, it's impossible to
266 * prevent that. Returning previous buffer contents may cause
267 * security problems inside the guest OS, if users can issue
268 * commands to the CDROM device. */
269 memset(pvBuf, '\0', *pcbBuf);
270 direction = SCSI_IOCTL_DATA_IN;
271 break;
272 case PDMMEDIATXDIR_TO_DEVICE:
273 direction = SCSI_IOCTL_DATA_OUT;
274 break;
275 default:
276 AssertMsgFailed(("enmTxDir invalid!\n"));
277 direction = SCSI_IOCTL_DATA_UNSPECIFIED;
278 }
279 memset(&Req, '\0', sizeof(Req));
280 Req.spt.Length = sizeof(Req.spt);
281 Req.spt.CdbLength = 12;
282 memcpy(Req.spt.Cdb, pbCmd, Req.spt.CdbLength);
283 Req.spt.DataBuffer = pvBuf;
284 Req.spt.DataTransferLength = *pcbBuf;
285 Req.spt.DataIn = direction;
286 Req.spt.TimeOutValue = (cTimeoutMillies + 999) / 1000; /* Convert to seconds */
287 Assert(cbSense <= sizeof(Req.aSense));
288 Req.spt.SenseInfoLength = (UCHAR)RT_MIN(sizeof(Req.aSense), cbSense);
289 Req.spt.SenseInfoOffset = RT_UOFFSETOF(struct _REQ, aSense);
290 if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_SCSI_PASS_THROUGH_DIRECT,
291 &Req, sizeof(Req), &Req, sizeof(Req), &cbReturned, NULL))
292 {
293 if (cbReturned > RT_UOFFSETOF(struct _REQ, aSense))
294 memcpy(pbSense, Req.aSense, cbSense);
295 else
296 memset(pbSense, '\0', cbSense);
297 /* Windows shares the property of not properly reflecting the actually
298 * transferred data size. See above. Assume that everything worked ok.
299 * Except if there are sense information. */
300 rc = (pbSense[2] & 0x0f) == SCSI_SENSE_NONE
301 ? VINF_SUCCESS
302 : VERR_DEV_IO_ERROR;
303 }
304 else
305 rc = RTErrConvertFromWin32(GetLastError());
306 Log2(("%s: scsistatus=%d bytes returned=%d tlength=%d\n", __FUNCTION__, Req.spt.ScsiStatus, cbReturned, Req.spt.DataTransferLength));
307
308 return rc;
309}
310
311
312DECLHIDDEN(size_t) drvHostBaseScsiCmdGetBufLimitOs(PDRVHOSTBASE pThis)
313{
314 RT_NOREF(pThis);
315
316 return WIN_SCSI_MAX_BUFFER_SIZE;
317}
318
319
320DECLHIDDEN(int) drvHostBaseGetMediaSizeOs(PDRVHOSTBASE pThis, uint64_t *pcb)
321{
322 int rc = VERR_GENERAL_FAILURE;
323
324 if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType))
325 {
326 DISK_GEOMETRY geom;
327 DWORD cbBytesReturned;
328 int cbSectors;
329
330 memset(&geom, 0, sizeof(geom));
331 rc = DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_DISK_GET_DRIVE_GEOMETRY,
332 NULL, 0, &geom, sizeof(geom), &cbBytesReturned, NULL);
333 if (rc) {
334 cbSectors = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack;
335 *pcb = cbSectors * geom.BytesPerSector;
336 rc = VINF_SUCCESS;
337 }
338 else
339 {
340 DWORD dwLastError;
341
342 dwLastError = GetLastError();
343 rc = RTErrConvertFromWin32(dwLastError);
344 Log(("DrvHostFloppy: IOCTL_DISK_GET_DRIVE_GEOMETRY(%s) failed, LastError=%d rc=%Rrc\n",
345 pThis->pszDevice, dwLastError, rc));
346 return rc;
347 }
348 }
349 else
350 {
351 /* use NT api, retry a few times if the media is being verified. */
352 IO_STATUS_BLOCK IoStatusBlock = {0};
353 FILE_FS_SIZE_INFORMATION FsSize= {0};
354 NTSTATUS rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice), &IoStatusBlock,
355 &FsSize, sizeof(FsSize), FileFsSizeInformation);
356 int cRetries = 5;
357 while (rcNt == STATUS_VERIFY_REQUIRED && cRetries-- > 0)
358 {
359 RTThreadSleep(10);
360 rcNt = NtQueryVolumeInformationFile((HANDLE)RTFileToNative(pThis->Os.hFileDevice), &IoStatusBlock,
361 &FsSize, sizeof(FsSize), FileFsSizeInformation);
362 }
363 if (rcNt >= 0)
364 {
365 *pcb = FsSize.TotalAllocationUnits.QuadPart * FsSize.BytesPerSector;
366 return VINF_SUCCESS;
367 }
368
369 /* convert nt status code to VBox status code. */
370 /** @todo Make conversion function!. */
371 switch (rcNt)
372 {
373 case STATUS_NO_MEDIA_IN_DEVICE: rc = VERR_MEDIA_NOT_PRESENT; break;
374 case STATUS_VERIFY_REQUIRED: rc = VERR_TRY_AGAIN; break;
375 }
376 LogFlow(("drvHostBaseGetMediaSize: NtQueryVolumeInformationFile -> %#lx\n", rcNt, rc));
377 }
378 return rc;
379}
380
381
382DECLHIDDEN(int) drvHostBaseReadOs(PDRVHOSTBASE pThis, uint64_t off, void *pvBuf, size_t cbRead)
383{
384 return RTFileReadAt(pThis->Os.hFileDevice, off, pvBuf, cbRead, NULL);
385}
386
387
388DECLHIDDEN(int) drvHostBaseWriteOs(PDRVHOSTBASE pThis, uint64_t off, const void *pvBuf, size_t cbWrite)
389{
390 return RTFileWriteAt(pThis->Os.hFileDevice, off, pvBuf, cbWrite, NULL);
391}
392
393
394DECLHIDDEN(int) drvHostBaseFlushOs(PDRVHOSTBASE pThis)
395{
396 return RTFileFlush(pThis->Os.hFileDevice);
397}
398
399
400DECLHIDDEN(int) drvHostBaseDoLockOs(PDRVHOSTBASE pThis, bool fLock)
401{
402 PREVENT_MEDIA_REMOVAL PreventMediaRemoval = {fLock};
403 DWORD cbReturned;
404 int rc;
405 if (DeviceIoControl((HANDLE)RTFileToNative(pThis->Os.hFileDevice), IOCTL_STORAGE_MEDIA_REMOVAL,
406 &PreventMediaRemoval, sizeof(PreventMediaRemoval),
407 NULL, 0, &cbReturned,
408 NULL))
409 rc = VINF_SUCCESS;
410 else
411 /** @todo figure out the return codes for already locked. */
412 rc = RTErrConvertFromWin32(GetLastError());
413
414 return rc;
415}
416
417
418DECLHIDDEN(int) drvHostBaseEjectOs(PDRVHOSTBASE pThis)
419{
420 int rc = VINF_SUCCESS;
421 RTFILE hFileDevice = pThis->Os.hFileDevice;
422 if (hFileDevice == NIL_RTFILE) /* obsolete crap */
423 rc = RTFileOpen(&hFileDevice, pThis->pszDeviceOpen, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
424 if (RT_SUCCESS(rc))
425 {
426 /* do ioctl */
427 DWORD cbReturned;
428 if (DeviceIoControl((HANDLE)RTFileToNative(hFileDevice), IOCTL_STORAGE_EJECT_MEDIA,
429 NULL, 0,
430 NULL, 0, &cbReturned,
431 NULL))
432 rc = VINF_SUCCESS;
433 else
434 rc = RTErrConvertFromWin32(GetLastError());
435
436 /* clean up handle */
437 if (hFileDevice != pThis->Os.hFileDevice)
438 RTFileClose(hFileDevice);
439 }
440 else
441 AssertMsgFailed(("Failed to open '%s' for ejecting this tray.\n", rc));
442
443 return rc;
444}
445
446
447DECLHIDDEN(void) drvHostBaseInitOs(PDRVHOSTBASE pThis)
448{
449 pThis->Os.hFileDevice = NIL_RTFILE;
450 pThis->Os.hwndDeviceChange = NULL;
451 pThis->Os.hThrdMediaChange = NIL_RTTHREAD;
452}
453
454
455DECLHIDDEN(int) drvHostBaseOpenOs(PDRVHOSTBASE pThis, bool fReadOnly)
456{
457 UINT uDriveType = GetDriveType(pThis->pszDevice);
458 switch (pThis->enmType)
459 {
460 case PDMMEDIATYPE_FLOPPY_360:
461 case PDMMEDIATYPE_FLOPPY_720:
462 case PDMMEDIATYPE_FLOPPY_1_20:
463 case PDMMEDIATYPE_FLOPPY_1_44:
464 case PDMMEDIATYPE_FLOPPY_2_88:
465 case PDMMEDIATYPE_FLOPPY_FAKE_15_6:
466 case PDMMEDIATYPE_FLOPPY_FAKE_63_5:
467 if (uDriveType != DRIVE_REMOVABLE)
468 {
469 AssertMsgFailed(("Configuration error: '%s' is not a floppy (type=%d)\n",
470 pThis->pszDevice, uDriveType));
471 return VERR_INVALID_PARAMETER;
472 }
473 break;
474 case PDMMEDIATYPE_CDROM:
475 case PDMMEDIATYPE_DVD:
476 if (uDriveType != DRIVE_CDROM)
477 {
478 AssertMsgFailed(("Configuration error: '%s' is not a cdrom (type=%d)\n",
479 pThis->pszDevice, uDriveType));
480 return VERR_INVALID_PARAMETER;
481 }
482 break;
483 case PDMMEDIATYPE_HARD_DISK:
484 default:
485 AssertMsgFailed(("enmType=%d\n", pThis->enmType));
486 return VERR_INVALID_PARAMETER;
487 }
488
489 int iBit = RT_C_TO_UPPER(pThis->pszDevice[0]) - 'A';
490 if ( iBit > 'Z' - 'A'
491 || pThis->pszDevice[1] != ':'
492 || pThis->pszDevice[2])
493 {
494 AssertMsgFailed(("Configuration error: Invalid drive specification: '%s'\n", pThis->pszDevice));
495 return VERR_INVALID_PARAMETER;
496 }
497 pThis->Os.fUnitMask = 1 << iBit;
498 RTStrAPrintf(&pThis->pszDeviceOpen, "\\\\.\\%s", pThis->pszDevice);
499 if (!pThis->pszDeviceOpen)
500 return VERR_NO_MEMORY;
501
502 uint32_t fFlags = (fReadOnly ? RTFILE_O_READ : RTFILE_O_READWRITE) | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
503 int rc = RTFileOpen(&pThis->Os.hFileDevice, pThis->pszDeviceOpen, fFlags);
504
505 if (RT_SUCCESS(rc))
506 {
507 /*
508 * Start the thread which will wait for the media change events.
509 */
510 rc = RTThreadCreate(&pThis->Os.hThrdMediaChange, drvHostBaseMediaThreadWin, pThis, 0,
511 RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "DVDMEDIA");
512 if (RT_FAILURE(rc))
513 {
514 AssertMsgFailed(("Failed to create poller thread. rc=%Rrc\n", rc));
515 return rc;
516 }
517
518 /*
519 * Wait for the thread to start up (!w32:) and do one detection loop.
520 */
521 rc = RTThreadUserWait(pThis->Os.hThrdMediaChange, 10000);
522 AssertRC(rc);
523
524 if (!pThis->Os.hwndDeviceChange)
525 return VERR_GENERAL_FAILURE;
526
527 DRVHostBaseMediaPresent(pThis);
528 }
529
530 return rc;
531}
532
533
534DECLHIDDEN(int) drvHostBaseMediaRefreshOs(PDRVHOSTBASE pThis)
535{
536 RT_NOREF(pThis);
537 return VINF_SUCCESS;
538}
539
540
541DECLHIDDEN(int) drvHostBaseQueryMediaStatusOs(PDRVHOSTBASE pThis, bool *pfMediaChanged, bool *pfMediaPresent)
542{
543 RT_NOREF3(pThis, pfMediaChanged, pfMediaPresent); /* We don't support the polling method. */
544 return VERR_NOT_SUPPORTED;
545}
546
547
548DECLHIDDEN(bool) drvHostBaseIsMediaPollingRequiredOs(PDRVHOSTBASE pThis)
549{
550 /* For Windows we alwys use an internal approach. */
551 RT_NOREF(pThis);
552 return false;
553}
554
555
556DECLHIDDEN(void) drvHostBaseDestructOs(PDRVHOSTBASE pThis)
557{
558 /*
559 * Terminate the thread.
560 */
561 if (pThis->Os.hThrdMediaChange != NIL_RTTHREAD)
562 {
563 int rc;
564 int cTimes = 50;
565 do
566 {
567 if (pThis->Os.hwndDeviceChange)
568 PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
569
570 rc = RTThreadWait(pThis->Os.hThrdMediaChange, 100, NULL);
571 } while (cTimes-- > 0 && rc == VERR_TIMEOUT);
572
573 if (RT_SUCCESS(rc))
574 pThis->Os.hThrdMediaChange = NIL_RTTHREAD;
575 }
576
577 /*
578 * Unlock the drive if we've locked it or we're in passthru mode.
579 */
580 if ( pThis->fLocked
581 && pThis->Os.hFileDevice != NIL_RTFILE
582 && pThis->pfnDoLock)
583 {
584 int rc = pThis->pfnDoLock(pThis, false);
585 if (RT_SUCCESS(rc))
586 pThis->fLocked = false;
587 }
588
589 if (pThis->Os.hwndDeviceChange)
590 {
591 if (SetWindowLongPtr(pThis->Os.hwndDeviceChange, GWLP_USERDATA, 0) == (LONG_PTR)pThis)
592 PostMessage(pThis->Os.hwndDeviceChange, WM_CLOSE, 0, 0); /* default win proc will destroy the window */
593 pThis->Os.hwndDeviceChange = NULL;
594 }
595
596 if (pThis->Os.hFileDevice != NIL_RTFILE)
597 {
598 int rc = RTFileClose(pThis->Os.hFileDevice);
599 AssertRC(rc);
600 pThis->Os.hFileDevice = NIL_RTFILE;
601 }
602}
603
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette