aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_disc/drivemngr.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_disc/drivemngr.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_disc/drivemngr.cpp')
-rw-r--r--Src/Plugins/Library/ml_disc/drivemngr.cpp1910
1 files changed, 1910 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_disc/drivemngr.cpp b/Src/Plugins/Library/ml_disc/drivemngr.cpp
new file mode 100644
index 00000000..b2d87fcc
--- /dev/null
+++ b/Src/Plugins/Library/ml_disc/drivemngr.cpp
@@ -0,0 +1,1910 @@
+#include "main.h"
+#include "./drivemngr.h"
+#include "./primosdk_helper.h"
+#include "./resource.h"
+#include "../nu/trace.h"
+#include "./dbt.h"
+#include "./spti.h"
+#include <setupapi.h>
+
+#include <imapi.h>
+#include <strsafe.h>
+
+#define LISTENER_CLASSNAME L"MLDISCLISTENER"
+#define LISTENER_WINDOWNAME L""
+
+#define POLLMEDIUMCHANGE_INTERVAL 2000
+#define POLLMEDIUMVALIDATE_INTERVAL 6000
+
+#define DMS_SUSPENDED 0x0000
+#define DMS_ACTIVE 0x0001
+
+#define WM_EX_QUIT (WM_APP + 1)
+
+typedef struct _MEDIUMINFO_I
+{
+ UINT msLastPolled; // last time medium info was polled
+ UINT serialNumber; // medium serialnumber
+} MEDIUMINFO_I;
+
+typedef struct _DRIVEINFO_I
+{
+ char cLetter; // drive letter
+ INT deviceNumber; // system assigned device number (unique till next reboot)
+ BOOL bMediumInserted; // if TRUE mediumInfo contains valid data
+ CHAR cMode; // drive mode
+ DWORD dwType; // drive type
+ LPWSTR pszDevName; // device name
+ HANDLE hThread; // device info thread
+ DWORD dwThreadId;
+ MEDIUMINFO_I mediumInfo;
+} DRIVEINFO_I;
+
+typedef struct _DRIVEMNGR
+{
+ HWND hwndListener;
+ DMNPROC callback;
+ UINT fState;
+ CRITICAL_SECTION csLock;
+
+ DRIVEINFO_I *pDrives;
+ INT nCount;
+ INT nAlloc;
+
+ HANDLE hPollingThread;
+ DWORD dwPollingThread;
+} DRIVEMNGR;
+
+typedef struct _DEVICEINFO
+{
+ CHAR cLetter;
+ LPWSTR pszDevName;
+ WCHAR szTargetPath[128];
+ WCHAR szVolumeName[64];
+ DWORD dwType;
+ INT deviceNumber;
+ INT opCode;
+} DEVICEINFO;
+
+static DRIVEMNGR *pMngr = NULL;
+
+
+static void CALLBACK APC_CheckDrives(ULONG_PTR param);
+static void CALLBACK APC_IsMediumChanged(ULONG_PTR param);
+
+static void CALLBACK APC_GetUnitInfo(ULONG_PTR param);
+static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param);
+static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param);
+static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param);
+static void CALLBACK APC_GetTitle(ULONG_PTR param);
+static void CALLBACK APC_DriveScan(ULONG_PTR param);
+static void CALLBACK APC_GetMCIInfo(ULONG_PTR param);
+static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param);
+static void CALLBACK APC_Eject(ULONG_PTR param);
+
+static DWORD CALLBACK InfoThread(LPVOID param);
+
+static DWORD CALLBACK PollingThread(LPVOID param);
+
+static void CALLBACK PollMediumInfo(ULONG_PTR param);
+
+static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+static CHAR CheckLetter(CHAR cLetter)
+{
+ if (cLetter < 'A' || cLetter > 'Z')
+ {
+ if (cLetter >= 'a' && cLetter <= 'z') return (cLetter - 0x20);
+ return 0;
+ }
+ return cLetter;
+}
+
+static LPCWSTR GetDeviceName(CHAR cLetter)
+{
+ LPCWSTR pszDevName;
+ if (!pMngr) return NULL;
+ pszDevName = NULL;
+
+ EnterCriticalSection(&pMngr->csLock);
+ for (int i = 0; i < pMngr->nCount; i++)
+ {
+ if (pMngr->pDrives[i].cLetter == cLetter)
+ {
+ pszDevName = pMngr->pDrives[i].pszDevName;
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ return pszDevName;
+}
+
+static BOOL IsPollingRequired(void)
+{
+ HKEY hKey;
+ LONG result;
+ BOOL bAutoRunEnabled;
+
+ bAutoRunEnabled = FALSE;
+
+ result = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Cdrom"), &hKey);
+ if (ERROR_SUCCESS == result)
+ {
+ DWORD value;
+ DWORD size;
+ size = sizeof(DWORD);
+ result = RegQueryValueEx(hKey, TEXT("AutoRun"), NULL, NULL, (LPBYTE)&value, &size);
+ if (ERROR_SUCCESS == result) bAutoRunEnabled = (0 != value);
+
+ RegCloseKey(hKey);
+ }
+ return !bAutoRunEnabled;
+
+}
+static CHAR Drive_LetterFromMask(ULONG unitmask)
+{
+ char i;
+ for (i = 0; i < 26; ++i)
+ {
+ if (unitmask & 0x1) break;
+ unitmask = unitmask >> 1;
+ }
+ return (i + 'A');
+}
+
+static BOOL Drive_Add(DEVICEINFO *pDevInfo)
+{
+ DRIVEINFO_I *pDrive;
+ if (!pMngr) return FALSE;
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ INT index, opCode;
+
+ opCode = 0;
+ for (index = 0; index < pMngr->nCount && pMngr->pDrives[index].cLetter != pDevInfo->cLetter; index++);
+ if (index != pMngr->nCount)
+ {
+ pDrive = &pMngr->pDrives[index];
+ if (pDrive->deviceNumber != pDevInfo->deviceNumber || pDrive->dwType != pDevInfo->dwType) opCode = 1;
+ }
+ else
+ {
+ if (pMngr->nCount == pMngr->nAlloc)
+ {
+ LPVOID data;
+ data = realloc(pMngr->pDrives, sizeof(DRIVEINFO_I)*(pMngr->nCount + 2));
+ if (!data)
+ {
+ LeaveCriticalSection(&pMngr->csLock);
+ return FALSE;
+ }
+ pMngr->pDrives = (DRIVEINFO_I*)data;
+ pMngr->nAlloc += 2;
+ }
+ pDrive = &pMngr->pDrives[pMngr->nCount];
+ pMngr->nCount++;
+
+ ZeroMemory(pDrive, sizeof(DRIVEINFO_I));
+ pDrive->cLetter = pDevInfo->cLetter;
+ opCode = 2;
+ }
+
+ if (opCode)
+ {
+ pDrive->deviceNumber = pDevInfo->deviceNumber;
+ pDrive->dwType = pDevInfo->dwType;
+ if (pDrive->pszDevName) free(pDrive->pszDevName);
+ pDrive->pszDevName = _wcsdup(pDevInfo->pszDevName);
+ }
+
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (opCode && pMngr->callback) pMngr->callback((2 == opCode) ? DMW_DRIVEADDED : DMW_DRIVECHANGED, pDevInfo->cLetter);
+
+ return TRUE;
+}
+
+static BOOL Drive_Remove(CHAR cLetter)
+{
+ INT index;
+ BOOL bReportChanges;
+ if (!pMngr) return FALSE;
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ bReportChanges = FALSE;
+ index = pMngr->nCount;
+ while (index-- && pMngr->pDrives[index].cLetter != cLetter);
+
+ if (-1 != index)
+ {
+ if (pMngr->pDrives[index].pszDevName) free(pMngr->pDrives[index].pszDevName);
+ if (index != pMngr->nCount - 1) MoveMemory(&pMngr->pDrives[index], &pMngr->pDrives[index + 1], sizeof(DRIVEINFO_I)*(pMngr->nCount - index));
+ pMngr->nCount--;
+ bReportChanges = TRUE;
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (bReportChanges && pMngr->callback) pMngr->callback(DMW_DRIVEREMOVED, cLetter);
+ return TRUE;
+}
+
+static HRESULT QueueInfoAPC(CHAR cLetter, PAPCFUNC pfnAPC, ULONG_PTR param)
+{
+ DWORD *pdwThreadId(NULL);
+ HRESULT hr(S_FALSE);
+ HANDLE *phThread(NULL);
+ static HANDLE hDrivesInfoThread = NULL;
+
+ if (NULL == pMngr) return E_FAIL;
+
+ EnterCriticalSection(&pMngr->csLock);
+ if (cLetter)
+ {
+ INT index = pMngr->nCount;
+ while (index-- && pMngr->pDrives[index].cLetter != cLetter);
+ if (-1 != index)
+ {
+ phThread = &pMngr->pDrives[index].hThread;
+ pdwThreadId = &pMngr->pDrives[index].dwThreadId;
+ }
+ }
+ else
+ {
+ phThread = &hDrivesInfoThread;
+ }
+
+ if (phThread)
+ {
+ if (!*phThread)
+ {
+ DWORD tid;
+ *phThread = CreateThread(NULL, 0, InfoThread, NULL, 0, &tid);
+ if (pdwThreadId) *pdwThreadId = tid;
+ Sleep(100);
+ }
+ if (*phThread)
+ {
+ if (0 == QueueUserAPC(pfnAPC, *phThread, param))
+ {
+ TRACE_LINE(TEXT("queue user apc failed"));
+ }
+ else hr = S_OK;
+ }
+ }
+
+ LeaveCriticalSection(&pMngr->csLock);
+
+ return hr;
+}
+
+static BOOL Medium_Add(CHAR cLetter, DWORD serial)
+{
+ INT index;
+ if (!pMngr) return FALSE;
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ index = pMngr->nCount;
+ while (index-- && pMngr->pDrives[index].cLetter != cLetter);
+ if (-1 != index)
+ {
+ pMngr->pDrives[index].bMediumInserted = TRUE;
+ pMngr->pDrives[index].mediumInfo.msLastPolled = 0;
+ pMngr->pDrives[index].mediumInfo.serialNumber = serial;
+ }
+
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (-1 != index)
+ {
+ if (-1 == serial) QueueInfoAPC(cLetter, APC_IsMediumChanged, (ULONG_PTR)cLetter);
+ if (pMngr->callback) pMngr->callback(DMW_MEDIUMARRIVED, cLetter);
+ }
+
+ return TRUE;
+}
+
+static BOOL Medium_Remove(CHAR cLetter)
+{
+ INT index;
+ if (!pMngr) return FALSE;
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ index = pMngr->nCount;
+ while (index-- && pMngr->pDrives[index].cLetter != cLetter);
+ if (-1 != index) pMngr->pDrives[index].bMediumInserted = FALSE;
+
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (-1 != index && pMngr->callback) pMngr->callback(DMW_MEDIUMREMOVED, cLetter);
+
+ return TRUE;
+}
+
+BOOL DriveManager_Initialize(DMNPROC DMNProc, BOOL bSuspended)
+{
+ WNDCLASSW wc = {0};
+ HINSTANCE hInstance;
+
+ if (pMngr || !DMNProc) return FALSE;
+
+ pMngr = (DRIVEMNGR*)calloc(1, sizeof(DRIVEMNGR));
+ if (!pMngr) return FALSE;
+
+ hInstance = GetModuleHandle(NULL);
+
+ if (!GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc))
+ {
+ wc.hInstance = hInstance;
+ wc.lpfnWndProc = ListenerWndProc;
+ wc.lpszClassName = LISTENER_CLASSNAME;
+ if (!RegisterClassW(&wc))
+ {
+ DriveManager_Uninitialize(0);
+ return FALSE;
+ }
+ }
+ pMngr->hwndListener = CreateWindowW(LISTENER_CLASSNAME, LISTENER_WINDOWNAME, WS_DISABLED, 0,0,0,0, HWND_DESKTOP, NULL, hInstance, 0L);
+ if (!pMngr->hwndListener)
+ {
+ DriveManager_Uninitialize(0);
+ return FALSE;
+ }
+ InitializeCriticalSection(&pMngr->csLock);
+ pMngr->callback = DMNProc;
+
+ return TRUE;
+}
+
+BOOL DriveManager_Uninitialize(INT msExitWaitTime)
+{
+ if (pMngr)
+ {
+ WNDCLASSW wc;
+ HINSTANCE hInstance;
+
+ if (pMngr->hwndListener) DestroyWindow(pMngr->hwndListener);
+
+ hInstance = GetModuleHandle(NULL);
+ if (GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc)) UnregisterClassW(LISTENER_CLASSNAME, hInstance);
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ for (int index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].hThread)
+ {
+ PostThreadMessage(pMngr->pDrives[index].dwThreadId, WM_EX_QUIT, 1, 0);
+ INT result = WaitForSingleObject(pMngr->pDrives[index].hThread, msExitWaitTime);
+ if (WAIT_TIMEOUT == result) TerminateThread(pMngr->pDrives[index].hThread, 1);
+ CloseHandle(pMngr->pDrives[index].hThread);
+ pMngr->pDrives[index].hThread = NULL;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (pMngr->hPollingThread)
+ {
+ PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0);
+ INT result = WaitForSingleObject(pMngr->hPollingThread, msExitWaitTime);
+ if (WAIT_TIMEOUT == result) TerminateThread(pMngr->hPollingThread, 1);
+ CloseHandle(pMngr->hPollingThread);
+ pMngr->hPollingThread = NULL;
+ }
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ if (pMngr->pDrives)
+ {
+ free(pMngr->pDrives);
+ }
+
+ DRIVEMNGR *managerInstance = pMngr;
+ pMngr = NULL;
+
+ LeaveCriticalSection(&managerInstance->csLock);
+ DeleteCriticalSection(&managerInstance->csLock);
+
+ free(managerInstance);
+
+ PrimoSDKHelper_Uninitialize();
+
+ }
+ return TRUE;
+}
+
+BOOL DriveManager_Suspend(void)
+{
+ if (!pMngr) return FALSE;
+
+ pMngr->fState = DMS_SUSPENDED;
+ if (pMngr->hPollingThread)
+ {
+ PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0);
+ pMngr->hPollingThread = NULL;
+ }
+ return TRUE;
+}
+
+BOOL DriveManager_Update(BOOL bAsync)
+{
+ if (bAsync) return (QueueInfoAPC(0, APC_DriveScan, 0) && QueueInfoAPC(0, PollMediumInfo, 0));
+ else
+ {
+ APC_DriveScan(0);
+ QueueInfoAPC(0, PollMediumInfo, 0);
+ }
+ return TRUE;
+}
+
+BOOL DriveManager_Resume(BOOL bUpdate)
+{
+ if (!pMngr) return FALSE;
+ pMngr->fState = DMS_ACTIVE;
+
+ EnterCriticalSection(&pMngr->csLock);
+ for (int index =0; index < pMngr->nCount; index++) pMngr->pDrives[index].mediumInfo.msLastPolled = 0;
+ LeaveCriticalSection(&pMngr->csLock);
+
+ APC_DriveScan(0);
+ QueueInfoAPC(0, PollMediumInfo, 0);
+
+ if (NULL == pMngr->hPollingThread && IsPollingRequired())
+ {
+ pMngr->hPollingThread = CreateThread(NULL, 0, PollingThread, NULL, 0, &pMngr->dwPollingThread);
+ }
+
+ return TRUE;
+}
+
+BOOL DriveManager_SetDriveMode(CHAR cLetter, CHAR cMode)
+{
+ BOOL report;
+ INT index;
+
+ index = -1;
+ report = FALSE;
+ cLetter = CheckLetter(cLetter);
+
+ if (pMngr && cLetter)
+ {
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == cLetter)
+ {
+ if (pMngr->pDrives[index].cMode != cMode)
+ {
+ pMngr->pDrives[index].cMode = cMode;
+ report = TRUE;
+ }
+ break;
+ }
+ }
+ if (index == pMngr->nCount) index = -1;
+ LeaveCriticalSection(&pMngr->csLock);
+ if (report && pMngr->callback) pMngr->callback(DMW_MODECHANGED, MAKEWORD(cLetter, cMode));
+ }
+
+ return (-1 != index);
+}
+
+CHAR DriveManager_GetDriveMode(CHAR cLetter)
+{
+ CHAR result;
+
+ result = DM_MODE_ERROR;
+ cLetter = CheckLetter(cLetter);
+
+ if (pMngr && cLetter)
+ {
+ INT index;
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == cLetter)
+ {
+ result = pMngr->pDrives[index].cMode;
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+ }
+ return result;
+}
+
+DWORD DriveManager_GetDriveType(CHAR cLetter)
+{
+ DWORD type;
+
+ type = DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN;
+ cLetter = CheckLetter(cLetter);
+
+ if (pMngr && cLetter)
+ {
+ INT index;
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == cLetter)
+ {
+ type = pMngr->pDrives[index].dwType;
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+ }
+ return type;
+}
+
+BOOL DriveManager_IsMediumInserted(CHAR cLetter)
+{
+ BOOL result;
+
+ result = FALSE;
+ cLetter = CheckLetter(cLetter);
+
+ if (pMngr && cLetter)
+ {
+ INT index;
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == cLetter)
+ {
+ result = pMngr->pDrives[index].bMediumInserted;
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+ }
+ return result;
+}
+
+INT DriveManager_GetDriveList(CHAR *pLetters, INT cchSize)
+{
+ INT r = 0;
+ if (!pLetters || !pMngr) return -1;
+ EnterCriticalSection(&pMngr->csLock);
+ for (int index =0; index < pMngr->nCount; index++)
+ {
+ *pLetters = pMngr->pDrives[index].cLetter;
+ pLetters++;
+ cchSize--;
+ r++;
+ if (0 == cchSize) break;
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+ return r;
+}
+
+static BOOL QueueInfoJob(PAPCFUNC pfnAPC, DM_NOTIFY_PARAM *pHeader)
+{
+ BOOL result(TRUE);
+ if (!pMngr || !pHeader) result = FALSE;
+
+ if (result)
+ {
+ HANDLE hProc = GetCurrentProcess();
+ pHeader->hReserved = 0;
+ result = (BOOL)DuplicateHandle(hProc, GetCurrentThread(), hProc, &pHeader->hReserved,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (!result) pHeader->hReserved = 0;
+ }
+
+ if (result)
+ {
+ CHAR cLetter = CheckLetter(pHeader->cLetter);
+ result = (cLetter && S_OK == QueueInfoAPC(cLetter, pfnAPC, (ULONG_PTR)pHeader));
+ }
+
+ if(!result && pHeader && pHeader->fnFree)
+ {
+ if (pHeader->hReserved) CloseHandle(pHeader->hReserved);
+ pHeader->fnFree(pHeader);
+ }
+ return result;
+}
+
+BOOL DriveManager_GetUnitInfo(DM_UNITINFO_PARAM *puip)
+{
+ return QueueInfoJob(APC_GetUnitInfo, (DM_NOTIFY_PARAM*)puip);
+}
+
+BOOL DriveManager_GetUnitInfo2(DM_UNITINFO2_PARAM *puip)
+{
+ return QueueInfoJob(APC_GetUnitInfo2, (DM_NOTIFY_PARAM*)puip);
+}
+
+BOOL DriveManager_GetDiscInfoEx(DM_DISCINFOEX_PARAM *pdip)
+{
+ return QueueInfoJob(APC_GetDiscInfoEx, (DM_NOTIFY_PARAM*)pdip);
+}
+BOOL DriveManager_GetDiscInfo2(DM_DISCINFO2_PARAM *pdip)
+{
+ return QueueInfoJob(APC_GetDiscInfo2, (DM_NOTIFY_PARAM*)pdip);
+}
+
+BOOL DriveManager_QueryTitle(DM_TITLE_PARAM *pdtp)
+{
+ return QueueInfoJob(APC_GetTitle, (DM_NOTIFY_PARAM*)pdtp);
+}
+
+BOOL DriveManager_GetMCIInfo(DM_MCI_PARAM *pmcip)
+{
+ return QueueInfoJob(APC_GetMCIInfo, (DM_NOTIFY_PARAM*)pmcip);
+}
+
+BOOL DriveManager_GetIMAPIInfo(DM_IMAPI_PARAM *pIMAPI)
+{
+ return QueueInfoJob(APC_GetIMAPIInfo, (DM_NOTIFY_PARAM*)pIMAPI);
+}
+BOOL DriveManager_Eject(CHAR cLetter, INT nCmd)
+{
+ if (!pMngr) return FALSE;
+ CHAR cLetter1 = CheckLetter(cLetter);
+
+ return (cLetter1 && QueueInfoAPC(cLetter1, APC_Eject, (ULONG_PTR)MAKELONG(cLetter, nCmd)));
+}
+
+BOOL DriveManager_IsUnitReady(CHAR cLetter, BOOL *pbReady)
+{
+ BYTE sc, asc, ascq;
+
+ BOOL bSuccess;
+ HANDLE hDevice;
+
+ *pbReady = FALSE;
+ hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+
+ if (INVALID_HANDLE_VALUE == hDevice) return FALSE;
+
+ bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3);
+ if (!bSuccess)
+ {
+ if (ERROR_SEM_TIMEOUT == GetLastError()) bSuccess = TRUE;
+ }
+ else if (0x00 == sc || (0x02 == sc && 0x3A == asc)) *pbReady = TRUE;
+
+ CloseHandle(hDevice);
+
+ return bSuccess;
+}
+
+static BOOL GetVolumeNameForVolumeMountPoint_DL(LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength)
+{
+ static BOOL (WINAPI *func)(LPCWSTR, LPWSTR, DWORD) = NULL;
+ if (!func)
+ {
+ UINT prevErrorMode;
+ HMODULE hModule;
+ prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ hModule = LoadLibraryW(L"Kernel32.dll");
+ SetErrorMode(prevErrorMode);
+ if (hModule)
+ {
+ func = (BOOL (WINAPI*)(LPCWSTR, LPWSTR, DWORD))GetProcAddress(hModule, "GetVolumeNameForVolumeMountPointW");
+ FreeLibrary(hModule);
+ }
+ }
+ return (func) ? func(lpszVolumeMountPoint, lpszVolumeName, cchBufferLength) : FALSE;
+}
+
+static DWORD GetDeviceNames(DEVICEINFO *pDevInfo, INT count)
+{
+ HANDLE hDevInfo;
+ SP_DEVICE_INTERFACE_DATA spiData;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_W *pspiDetailData;
+ DWORD dwErrorCode, dwReqSize, dwDetailSize;
+ wchar_t volume[128], szDosName[] = L"X:\\", szDosName1[] = L"X:\\";
+
+ if (!pDevInfo || !count) return ERROR_INVALID_DATA;
+
+ for (int i = 0; i < count; i++)
+ {
+ szDosName[0] = pDevInfo[i].cLetter;
+ GetVolumeNameForVolumeMountPoint_DL(szDosName, pDevInfo[i].szVolumeName, sizeof(pDevInfo[i].szVolumeName)/sizeof(wchar_t));
+ szDosName1[0] = pDevInfo[i].cLetter;
+ QueryDosDeviceW(szDosName1, pDevInfo[i].szTargetPath, sizeof(pDevInfo[i].szTargetPath)/sizeof(wchar_t));
+ }
+
+ hDevInfo = SetupDiGetClassDevs((LPGUID)&CdRomClassGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE));
+ if (INVALID_HANDLE_VALUE == hDevInfo) return GetLastError();
+
+ dwDetailSize = 0;
+ pspiDetailData = NULL;
+ spiData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ dwErrorCode = 0;
+
+ for (int index = 0; !dwErrorCode; index++)
+ {
+ BOOL bResult = SetupDiEnumDeviceInterfaces(hDevInfo, 0, (LPGUID)&CdRomClassGuid, index, &spiData);
+ if (!bResult)
+ {
+ dwErrorCode = GetLastError();
+ break;
+ }
+
+ bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, NULL, 0, &dwReqSize, NULL);
+ if (!bResult)
+ {
+ dwErrorCode = GetLastError();
+ if (ERROR_INSUFFICIENT_BUFFER != dwErrorCode) break;
+ dwErrorCode = 0;
+ }
+ dwReqSize += 2*sizeof(wchar_t);
+ if (dwReqSize > dwDetailSize)
+ {
+ LPVOID data;
+ data = realloc(pspiDetailData, dwReqSize);
+ if (!data) { dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; break; }
+ pspiDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA*)data;
+ dwDetailSize = dwReqSize;
+ }
+
+ pspiDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+ bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, pspiDetailData, dwDetailSize, NULL, NULL);
+ if (!bResult)
+ {
+ dwErrorCode = GetLastError();
+ break;
+ }
+
+ INT cchName;
+ cchName = lstrlenW(pspiDetailData->DevicePath);
+ pspiDetailData->DevicePath[cchName] = L'\\';
+ pspiDetailData->DevicePath[cchName + 1] = 0x00;
+
+ if(GetVolumeNameForVolumeMountPoint_DL(pspiDetailData->DevicePath, volume, sizeof(volume)/sizeof(wchar_t)))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (!pDevInfo[i].pszDevName && 0 == lstrcmpW(volume, pDevInfo[i].szVolumeName))
+ {
+ pDevInfo[i].pszDevName = (LPWSTR)calloc((cchName + 1), sizeof(wchar_t));
+ if (pDevInfo[i].pszDevName) StringCchCopyNW(pDevInfo[i].pszDevName, cchName + 1, pspiDetailData->DevicePath, cchName);
+ break;
+ }
+ }
+ }
+ }
+ if (pspiDetailData) free(pspiDetailData);
+ SetupDiDestroyDeviceInfoList(hDevInfo);
+
+ for (int i = 0; i < count; i++)
+ {
+ if (!pDevInfo[i].pszDevName)
+ {
+ wchar_t szDevName[] = L"\\\\.\\x:";
+ szDevName[4] = pDevInfo[i].cLetter;
+ pDevInfo[i].pszDevName = (LPWSTR)calloc(sizeof(szDevName) + 2, sizeof(wchar_t));
+ if (pDevInfo[i].pszDevName) StringCbCopyW(pDevInfo[i].pszDevName, sizeof(szDevName) + 2, szDevName);
+ }
+ }
+
+ return dwErrorCode;
+}
+
+static void GetDeviceCaps(DEVICEINFO *pDevInfo, INT count)
+{
+ for( int i = 0; i < count; i++)
+ {
+ pDevInfo[i].dwType = ((pDevInfo[i].dwType & 0x0000FFFF) | DRIVE_CAP_UNKNOWN);
+ }
+
+ // TODO come back to this later on, but for the moment not seeing any noticeable issues
+ // with disabling this and instead and instead it helps prevent random trk****.tmp
+ // files being generated and also seems to fix the crash on start people have here
+ /*IDiscMaster *pdm;
+ IDiscRecorder *pdr;
+ IEnumDiscRecorders *per;
+ ULONG nActual;
+ HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm);
+ if (SUCCEEDED(hr))
+ {
+ // TODO determine why this is causing trk*.tmp files to be created when called
+ // which ends up spamming the %temp% folder everytime Winamp starts :o(
+ hr = pdm->Open();
+ if (SUCCEEDED(hr))
+ {
+ IEnumDiscMasterFormats *pef;
+ hr = pdm->EnumDiscMasterFormats(&pef);
+ if (SUCCEEDED(hr))
+ {
+ IID pFormats[2];
+ hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual);
+ if (SUCCEEDED(hr))
+ {
+ while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; }
+ if (nActual != ((ULONG)-1))
+ {
+ IRedbookDiscMaster *pdf;
+ hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf);
+ if (SUCCEEDED(hr))
+ {
+ pdf->Release();
+ hr = pdm->EnumDiscRecorders(&per);
+ if (SUCCEEDED(hr))
+ {
+ while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0)
+ {
+ BSTR bstrPath;
+ hr = pdr->GetPath(&bstrPath);
+ if (SUCCEEDED(hr))
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (0 == lstrcmpW(pDevInfo[i].szTargetPath, bstrPath))
+ {
+ LONG type;
+ if (SUCCEEDED(pdr->GetRecorderType(&type)))
+ {
+ pDevInfo[i].dwType &= 0x0000FFFF;
+ switch(type)
+ {
+ case RECORDER_CDR: pDevInfo[i].dwType |= DRIVE_CAP_R; break;
+ case RECORDER_CDRW: pDevInfo[i].dwType |= DRIVE_CAP_RW; break;
+ }
+ }
+ break;
+ }
+ }
+ if (bstrPath) SysFreeString(bstrPath);
+ }
+ pdr->Release();
+ }
+ per->Release();
+ }
+ }
+ }
+ }
+ pef->Release();
+ }
+ pdm->Close();
+ }
+ pdm->Release();
+ }
+ else
+ {
+ }*/
+}
+
+static void Listener_OnDeviceChange(HWND hwnd, UINT nType, DWORD_PTR dwData)
+{
+ DEV_BROADCAST_HDR *phdr;
+
+ switch(nType)
+ {
+ case DBT_DEVICEARRIVAL:
+ phdr = (DEV_BROADCAST_HDR*)dwData;
+ if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype)
+ {
+ DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr;
+ if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Add(Drive_LetterFromMask(pvol->dbcv_unitmask), (DWORD)-1);
+ else if (0 == pvol->dbcv_flags)
+ {
+ char root[] = "X:\\";
+ root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask);
+ if (DRIVE_CDROM == GetDriveTypeA(root)) QueueInfoAPC(0, APC_CheckDrives, (ULONG_PTR)root[0]);
+ }
+ }
+ break;
+ case DBT_DEVICEREMOVECOMPLETE:
+ phdr = (DEV_BROADCAST_HDR*)dwData;
+ if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype)
+ {
+ DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr;
+ if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Remove(Drive_LetterFromMask(pvol->dbcv_unitmask));
+ else if (0 == pvol->dbcv_flags)
+ {
+ char root[] = "X:\\";
+ root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask);
+ if (DRIVE_CDROM == GetDriveTypeA(root)) Drive_Remove(root[0]);
+ }
+ }
+ break;
+ }
+}
+
+static DWORD CALLBACK InfoThread(LPVOID param)
+{
+ MSG msg;
+ DWORD start, status, timeout, result(0);
+ BOOL bComInit, run(TRUE);
+ HANDLE hTemp(NULL);
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+ bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
+
+ timeout = 20000; // 20 seconds delay
+ start = GetTickCount();
+
+ while(run)
+ {
+ DWORD elapsed = GetTickCount() - start;
+ if (elapsed < timeout)
+ status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed,
+ QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ else status = WAIT_TIMEOUT;
+
+ switch(status)
+ {
+ case WAIT_FAILED:
+ if (bComInit) CoUninitialize();
+ return (DWORD)-1;
+ case WAIT_TIMEOUT:
+ if (NULL != pMngr)
+ {
+ EnterCriticalSection(&pMngr->csLock);
+ start = GetCurrentThreadId();
+ hTemp = NULL;
+
+ for (int i = pMngr->nCount - 1; i >= 0; i--)
+ {
+ if (pMngr->pDrives[i].dwThreadId == start)
+ {
+ pMngr->pDrives[i].dwThreadId = 0;
+ hTemp = pMngr->pDrives[i].hThread;
+ pMngr->pDrives[i].hThread = NULL;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ //while (WAIT_IO_COMPLETION == WaitForMultipleObjectsEx(0, NULL, TRUE, 0, TRUE));
+ while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION);
+ }
+ result = 2;
+ run = FALSE;
+ break;
+ case WAIT_IO_COMPLETION: start = GetTickCount(); break;
+ case WAIT_OBJECT_0:
+ while (run && PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ switch(msg.message)
+ {
+ case WM_QUIT:
+ result = (DWORD)msg.wParam;
+ run = FALSE;
+ break;
+ case WM_EX_QUIT:
+ PostQuitMessage((INT)msg.wParam);
+ break;
+ default:
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (bComInit) CoUninitialize();
+ if (2 == result && hTemp) CloseHandle(hTemp);
+ hTemp = NULL;
+ return result;
+}
+
+static DWORD CALLBACK PollingThread(LPVOID param)
+{
+ MSG msg;
+ DWORD status, timeout;
+ BOOL bComInit;
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
+ bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
+
+ timeout = POLLMEDIUMCHANGE_INTERVAL;
+
+ for(;;)
+ {
+ DWORD elapsed, start = GetTickCount();
+ while ((elapsed = GetTickCount() - start) < timeout)
+ {
+ status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed,
+ QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
+ switch(status)
+ {
+ case WAIT_FAILED:
+ if (bComInit) CoUninitialize();
+ return (DWORD)-1;
+ case WAIT_TIMEOUT: PollMediumInfo(0); break;
+ case WAIT_OBJECT_0:
+ while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ switch(msg.message)
+ {
+ case WM_QUIT:
+ if (bComInit) CoUninitialize();
+ return (DWORD)msg.wParam;
+ case WM_EX_QUIT:
+ PostQuitMessage((INT)msg.wParam);
+ break;
+ default:
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void CALLBACK PollMediumInfo(ULONG_PTR param)
+{
+ char letters[32] = {0};
+ LPCWSTR pszDevName[32] = {0};
+ INT index, count;
+ if (!pMngr) return;
+
+ count = 0;
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (DM_MODE_BURNING != pMngr->pDrives[index].cMode && DM_MODE_RIPPING != pMngr->pDrives[index].cMode)
+ {
+ letters[count] = pMngr->pDrives[index].cLetter;
+ pszDevName[count] = pMngr->pDrives[index].pszDevName;
+ count++;
+ }
+ }
+
+ LeaveCriticalSection(&pMngr->csLock);
+
+ while(count--)
+ {
+ HANDLE hDevice = CreateFileW(pszDevName[count], GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+
+ if (INVALID_HANDLE_VALUE != hDevice)
+ {
+ BYTE sc, asc, ascq;
+ BOOL bReady, bReportChanges, bNeedRecheck;
+ DWORD ticks;
+
+ bReportChanges = FALSE;
+ bNeedRecheck = FALSE;
+
+ if(!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 2))
+ {
+ bReady = FALSE;
+ }
+ else bReady = (0x00 == sc || (0x02 == sc && 0x3A == asc));
+
+ CloseHandle(hDevice);
+
+ EnterCriticalSection(&pMngr->csLock);
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == letters[count])
+ {
+ ticks = GetTickCount();
+ if (pMngr->pDrives[index].bMediumInserted &&
+ (ticks - pMngr->pDrives[index].mediumInfo.msLastPolled) > POLLMEDIUMVALIDATE_INTERVAL) bNeedRecheck = TRUE;
+ pMngr->pDrives[index].mediumInfo.msLastPolled = ticks;
+
+ if (bReady && ((0x00 == sc) != pMngr->pDrives[index].bMediumInserted)) bReportChanges = TRUE;
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (bReportChanges)
+ {
+ if (0 == sc) Medium_Add(letters[count], (DWORD)-1);
+ else Medium_Remove(letters[count]);
+ }
+ else if (bNeedRecheck)
+ {
+ QueueInfoAPC(letters[count], APC_IsMediumChanged, (DWORD_PTR)letters[count]);
+ }
+
+ }
+ }
+}
+
+
+static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_DEVICECHANGE:
+ Listener_OnDeviceChange(hwnd, (UINT)wParam, (DWORD_PTR)lParam);
+ break;
+ }
+ return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+}
+
+static void CALLBACK APC_CheckDrives(ULONG_PTR param)
+{
+ INT index, result, count;
+ DWORD unitmask, dwOutput;
+ STORAGE_DEVICE_NUMBER sdn;
+ DEVICEINFO *pDevInfo;
+ BYTE buffer[4096] = {0};
+
+ if (!pMngr) return;
+
+ unitmask = (DWORD)param;
+ count = 0;
+ for (int i = 0; i < 26; i++) {if (0x1 & (unitmask >> i)) count++;}
+ if (!count) return;
+
+ pDevInfo = (DEVICEINFO*)calloc(count, sizeof(DEVICEINFO));
+ if (!pDevInfo) return;
+
+ index = 0;
+ for (int i = 0; i < 26; i++)
+ {
+ if (0x1 & unitmask)
+ {
+ pDevInfo[index].cLetter = (CHAR)(('A' + i));
+ index++;
+ if (index == count) break;
+ }
+ unitmask = unitmask >> 1;
+ }
+
+ GetDeviceNames(pDevInfo, count);
+
+ for (int i = 0; i < count; i++)
+ {
+ HANDLE hDevice = CreateFileW(pDevInfo[i].pszDevName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+
+ if (INVALID_HANDLE_VALUE != hDevice)
+ {
+ ZeroMemory(&sdn, sizeof(STORAGE_DEVICE_NUMBER));
+ result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(STORAGE_DEVICE_NUMBER), &dwOutput, NULL);
+ pDevInfo->deviceNumber = (result) ? sdn.DeviceNumber : -1;
+
+ ZeroMemory(&buffer, sizeof(buffer)/sizeof(BYTE));
+ result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0, buffer, sizeof(buffer)/sizeof(BYTE), &dwOutput, NULL);
+ if (result && buffer && (FILE_DEVICE_DVD & ((GET_MEDIA_TYPES*)buffer)->DeviceType)) pDevInfo[i].dwType = DRIVE_TYPE_DVD;
+ else pDevInfo[i].dwType = DRIVE_TYPE_CD;
+
+ CloseHandle(hDevice);
+ }
+ }
+
+ GetDeviceCaps(pDevInfo, count);
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ for (int i = 0; i < count; i++)
+ {
+ pDevInfo[i].opCode = 0;
+ for (index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == pDevInfo[i].cLetter)
+ {
+ if (-1 == pMngr->pDrives[index].deviceNumber || pMngr->pDrives[index].deviceNumber != pDevInfo[i].deviceNumber)
+ pDevInfo[i].opCode = 1;
+ break;
+ }
+ }
+ if (pMngr->nCount == index) pDevInfo[i].opCode = 2;
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ for (int i = 0; i < count; i++)
+ {
+ if (pDevInfo[i].opCode) Drive_Add(&pDevInfo[i]);
+ }
+
+ if (pDevInfo)
+ {
+ for (int i = 0; i<count; i++)
+ {
+ if (pDevInfo[i].pszDevName) free(pDevInfo[i].pszDevName);
+ }
+ free(pDevInfo);
+ }
+}
+
+static void CALLBACK APC_IsMediumChanged(ULONG_PTR param)
+{
+ INT opCode;
+ DWORD serial;
+
+ wchar_t devname[4] = L"X:\\";
+
+ if (!pMngr) return;
+
+ opCode = 0;
+ devname[0] = (char)(0xFF & param);
+ if (devname[0])
+ {
+ BOOL result;
+
+ serial = 0;
+ result = GetVolumeInformationW(devname, NULL, 0, &serial, NULL, NULL, NULL, 0);
+ if (!result) serial = 0; // perhaps this is empty recordable disc
+
+ EnterCriticalSection(&pMngr->csLock);
+
+ for (INT index =0; index < pMngr->nCount; index++)
+ {
+ if (pMngr->pDrives[index].cLetter == (char)param )
+ {
+ pMngr->pDrives[index].mediumInfo.msLastPolled = GetTickCount();
+ if (!pMngr->pDrives[index].bMediumInserted && result) opCode = 0x02;
+ else if (pMngr->pDrives[index].mediumInfo.serialNumber != serial)
+ {
+ if (-1 == pMngr->pDrives[index].mediumInfo.serialNumber) pMngr->pDrives[index].mediumInfo.serialNumber = serial;
+ else opCode = 0x03;
+ }
+ break;
+ }
+ }
+ LeaveCriticalSection(&pMngr->csLock);
+
+ if (0x01 & opCode) Medium_Remove((char)param);
+ if (0x02 & opCode) Medium_Add((char)param, serial);
+ }
+}
+
+static void CALLBACK APC_AsyncOp_Complete(ULONG_PTR param)
+{
+ DM_NOTIFY_PARAM *phdr = (DM_NOTIFY_PARAM*)param;
+ if (phdr->hReserved)
+ {
+ CloseHandle(phdr->hReserved);
+ phdr->hReserved = NULL;
+ }
+
+ if (phdr->callback)
+ {
+ if (phdr->uMsg)
+ {
+ if (IsWindow((HWND)phdr->callback)) SendMessageW((HWND)phdr->callback, phdr->uMsg, (WPARAM)DMW_OPCOMPLETED, (LPARAM)phdr);
+ }
+ else ((DMNPROC)phdr->callback)(DMW_OPCOMPLETED, (INT_PTR)param);
+ }
+
+ if (phdr->fnFree)
+ {
+ phdr->fnFree(phdr);
+ }
+}
+
+static void AsycOp_Complete(DM_NOTIFY_PARAM *param)
+{
+ if (param) QueueUserAPC(APC_AsyncOp_Complete, param->hReserved, (ULONG_PTR)param);
+}
+
+static void CALLBACK APC_GetUnitInfo(ULONG_PTR param)
+{
+ DWORD unit;
+ DM_UNITINFO_PARAM *puip;
+ puip = (DM_UNITINFO_PARAM*)param;
+
+ puip->header.opCode = DMOP_UNITINFO;
+
+ unit = CheckLetter(puip->header.cLetter);
+
+ if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE;
+ else
+ {
+ DWORD ready = 0;
+ CHAR buffer[512] = {0};
+
+ puip->header.result = PrimoSDKHelper_UnitInfo(&unit, &puip->dwType,
+ ((DMF_DESCRIPTION & puip->header.fFlags) || (DMF_FIRMWARE & puip->header.fFlags)) ? (BYTE*)buffer: NULL,
+ (DMF_READY & puip->header.fFlags) ? &ready : NULL);
+
+ if (PRIMOSDK_OK == puip->header.result)
+ {
+ if (DMF_READY & puip->header.fFlags) puip->bReady = (0 != ready);
+
+ if (DMF_DESCRIPTION & puip->header.fFlags)
+ {
+ INT len = lstrlenA(buffer);
+ if (len > 5) len -= 5;
+ if (!puip->pszDesc || puip->cchDesc < (len + 1)) puip->cchDesc = -(len + 1);
+ else
+ {
+ StringCchCopyNA(puip->pszDesc, puip->cchDesc, buffer, len);
+ puip->cchDesc = len;
+ }
+ }
+ if (DMF_FIRMWARE & puip->header.fFlags)
+ {
+ LPSTR p;
+ INT len = lstrlenA(buffer);
+ p = buffer + (len - ((len > 5) ? 4 : 0));
+ if (!puip->pszFirmware || puip->cchFirmware < 4) puip->cchFirmware = -4;
+ else
+ {
+ StringCchCopyA(puip->pszFirmware, puip->cchFirmware, p);
+ puip->cchFirmware = 4;
+ }
+ }
+ }
+ }
+ AsycOp_Complete(&puip->header);
+}
+
+static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param)
+{
+ DWORD unit;
+ DM_UNITINFO2_PARAM *puip;
+
+ puip = (DM_UNITINFO2_PARAM*)param;
+ puip->header.opCode = DMOP_UNITINFO2;
+ unit = CheckLetter(puip->header.cLetter);
+
+ if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE;
+ else
+ {
+ BOOL bReady;
+ DWORD szTypes[32], rfu;
+
+ if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
+ {
+ SleepEx(1000, TRUE);
+ QueueUserAPC(APC_GetUnitInfo2, GetCurrentThread(), param);
+ return;
+ }
+
+ puip->header.result = PrimoSDKHelper_UnitInfo2(&unit, szTypes, &puip->dwClassId, &puip->dwBusType, &rfu);
+ if (PRIMOSDK_OK == puip->header.result)
+ {
+ if (DMF_TYPES & puip->header.fFlags)
+ {
+ INT len;
+ for (len = 0; szTypes[len] != 0xFFFFFFFF; len++);
+
+ if (!puip->pdwTypes || puip->nTypes < len) puip->nTypes = -len;
+ else
+ {
+ puip->nTypes = len;
+ if (len) CopyMemory(puip->pdwTypes, szTypes, sizeof(DWORD)*len);
+ }
+ }
+ }
+ }
+ AsycOp_Complete(&puip->header);
+}
+static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param)
+{
+ DWORD unit;
+ DM_DISCINFOEX_PARAM *pdip;
+
+ pdip = (DM_DISCINFOEX_PARAM*)param;
+ pdip->header.opCode = DMOP_DISCINFO;
+ unit = CheckLetter(pdip->header.cLetter);
+
+ if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE;
+ else
+ {
+ BOOL bReady;
+ DWORD dwFlags, dwErasable;
+
+ if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
+ {
+ SleepEx(1000, TRUE);
+ QueueUserAPC(APC_GetDiscInfoEx, GetCurrentThread(), param);
+ return;
+ }
+
+ dwFlags = (DMF_DRIVEMODE_TAO & pdip->header.fFlags);
+ pdip->header.result = PrimoSDKHelper_DiscInfoEx(&unit, dwFlags,
+ (DMF_MEDIUMTYPE & pdip->header.fFlags) ? &pdip->dwMediumType : NULL,
+ (DMF_MEDIUMFORMAT & pdip->header.fFlags) ? &pdip->dwMediumFormat : NULL,
+ &dwErasable,
+ (DMF_TRACKS & pdip->header.fFlags) ? &pdip->dwTracks: NULL,
+ (DMF_USED & pdip->header.fFlags) ? &pdip->dwUsed : NULL,
+ (DMF_FREE & pdip->header.fFlags) ? &pdip->dwFree : NULL);
+
+ if (PRIMOSDK_OK == pdip->header.result) pdip->bErasable = (0 != dwErasable);
+ }
+
+ AsycOp_Complete(&pdip->header);
+}
+
+static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param)
+{
+ DWORD unit;
+ DM_DISCINFO2_PARAM *pdip;
+
+ pdip = (DM_DISCINFO2_PARAM*)param;
+ pdip->header.opCode = DMOP_DISCINFO2;
+ unit = CheckLetter(pdip->header.cLetter);
+
+ if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE;
+ else
+ {
+ DWORD rfu, medium, protectedDVD, flags;
+
+ BOOL bReady;
+ if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
+ {
+ SleepEx(1000, TRUE);
+ QueueUserAPC(APC_GetDiscInfo2, GetCurrentThread(), param);
+ return;
+ }
+
+ pdip->header.result = PrimoSDKHelper_DiscInfo2(&unit,
+ (DMF_MEDIUM & pdip->header.fFlags) ? &pdip->dwMedium : (DMF_MEDIUMEX & pdip->header.fFlags) ? &medium : NULL,
+ (DMF_PROTECTEDDVD & pdip->header.fFlags) ? &protectedDVD : NULL,
+ (DMF_PACKETWRITTEN & pdip->header.fFlags) ? &flags : NULL,
+ (DMF_MEDIUMEX & pdip->header.fFlags) ? &pdip->dwMediumEx : NULL,
+ &rfu);
+ if (PRIMOSDK_OK == pdip->header.result)
+ {
+ if (DMF_PROTECTEDDVD & pdip->header.fFlags) pdip->bProtectedDVD = (0 != protectedDVD);
+ if (DMF_PACKETWRITTEN & pdip->header.fFlags) pdip->bPacketWritten = (0 != (PRIMOSDK_PACKETWRITTEN & protectedDVD));
+ }
+
+ }
+ AsycOp_Complete(&pdip->header);
+}
+
+static void CALLBACK APC_GetTitle(ULONG_PTR param)
+{
+ CHAR cLetter;
+ DM_TITLE_PARAM *pdtp;
+
+ pdtp = (DM_TITLE_PARAM*)param;
+ pdtp->header.opCode = DMOP_TITLE;
+ cLetter = CheckLetter(pdtp->header.cLetter);
+
+ pdtp->header.result = PRIMOSDK_CMDSEQUENCE;
+ if (cLetter && pdtp->pszTitle)
+ {
+ wchar_t name[] = L"X:\\";
+ MCIDEVICEID devId;
+ MCI_OPEN_PARMS op = {0};
+ MCI_GENERIC_PARMS gp = {0};
+ MCI_STATUS_PARMS sp = {0};
+
+ name[0] = cLetter;
+
+ op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO;
+ op.lpstrElementName = name;
+
+ if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op))
+ {
+ HRESULT hr;
+
+ devId = op.wDeviceID;
+ sp.dwItem = MCI_STATUS_MEDIA_PRESENT;
+ INT present = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
+
+ if (present)
+ {
+ INT nTracks;
+ BOOL bAudio;
+ wchar_t szVolume[256] = {0};
+ // check if we have at least one audio track
+ sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
+ nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1;
+ bAudio = FALSE;
+
+ if (nTracks > 0)
+ {
+ sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
+ for (sp.dwTrack = 1; sp.dwTrack <= (UINT)nTracks && !bAudio; sp.dwTrack++)
+ {
+ mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
+ bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn);
+ }
+ if (bAudio) WASABI_API_LNGSTRINGW_BUF(IDS_CD_AUDIO, szVolume, sizeof(szVolume)/sizeof(wchar_t));
+ else
+ {
+ INT result;
+ wchar_t devname[4] = L"X:\\";
+ devname[0] = cLetter;
+ result = GetVolumeInformationW(devname, szVolume, sizeof(szVolume)/sizeof(wchar_t), NULL, NULL, NULL, NULL, 0);
+ if (!result) WASABI_API_LNGSTRINGW_BUF(IDS_DISC_DATA, szVolume, sizeof(szVolume)/sizeof(wchar_t));
+ }
+ }
+ else WASABI_API_LNGSTRINGW_BUF(IDS_DISC_BLANK, szVolume, sizeof(szVolume)/sizeof(wchar_t));
+
+ hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s (%c:)", szVolume, cLetter);
+ }
+ else
+ {
+ INT nDriveType, nDriveCap;
+ DWORD type;
+ wchar_t szDriveType[32] = {0}, szDriveCap[64] = {0};
+
+ type = DriveManager_GetDriveType(cLetter);
+ if ((DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN) == type) type = DRIVE_TYPE_CD;
+
+ nDriveCap = ((DRIVE_CAP_R | DRIVE_CAP_RW) & type) ? IDS_RECORDER_CAP : IDS_DRIVE_CAP;
+ nDriveType = (IDS_DRIVE_CAP == nDriveCap && (DRIVE_TYPE_DVD & type)) ? IDS_DVD : IDS_CD;
+
+ WASABI_API_LNGSTRINGW_BUF(nDriveType, szDriveType, sizeof(szDriveType)/sizeof(wchar_t));
+ WASABI_API_LNGSTRINGW_BUF(nDriveCap, szDriveCap, sizeof(szDriveCap)/sizeof(wchar_t));
+ hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s %s (%C:)", szDriveType, szDriveCap, cLetter);
+ }
+ pdtp->header.result = hr;
+ mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp);
+ }
+ }
+ AsycOp_Complete(&pdtp->header);
+}
+
+static void CALLBACK APC_DriveScan(ULONG_PTR param)
+{
+ char i;
+ char root[] = "A:\\";
+ DWORD unitmask;
+ DEVICEINFO di = {0};
+
+ /// detect drives
+ unitmask = GetLogicalDrives();
+
+ di.deviceNumber = -1;
+ di.dwType = DRIVE_TYPE_CD;
+
+ for (i = 0; i < 26; ++i)
+ {
+ if (0x1 & (unitmask >> i))
+ {
+ root[0] = ('A' + i);
+ if(DRIVE_CDROM != GetDriveTypeA(root)) unitmask &= ~(1 << i);
+ else
+ {
+ di.cLetter = root[0];
+ Drive_Add(&di);
+ }
+ }
+ }
+ APC_CheckDrives((ULONG_PTR)unitmask);
+}
+
+#define MAX_TEST_ATTEMPT 20
+
+static void CALLBACK APC_Eject(ULONG_PTR param)
+{
+ INT nCmd;
+ CHAR cLetter;
+ BYTE sc(0), asc(0), ascq(0);
+
+ nCmd = HIWORD(param);
+ cLetter = CheckLetter((CHAR)param);
+
+ if (cLetter && DM_MODE_READY == DriveManager_GetDriveMode(cLetter))
+ {
+ BOOL bSuccess;
+ HANDLE hDevice;
+
+ hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
+ if (INVALID_HANDLE_VALUE != hDevice)
+ {
+ DWORD dwOutput;
+ LARGE_INTEGER start, finish;
+
+ bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3);
+ if (!bSuccess && ERROR_SEM_TIMEOUT == GetLastError())
+ {
+ bSuccess = TRUE;
+ sc = 0xFF;
+ }
+
+ if (bSuccess && (0 == sc || (0x02 == sc && 0x3A == asc)))
+ {
+ INT opCode;
+ opCode = (DM_EJECT_REMOVE == nCmd || 0x00 == sc || (0x3A == asc && 0x01 == ascq)) ?
+ IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA;
+
+ QueryPerformanceCounter(&start);
+ bSuccess = DeviceIoControl(hDevice, opCode, NULL, 0, NULL, 0, &dwOutput, NULL);
+ QueryPerformanceCounter(&finish);
+
+ if (bSuccess && DM_EJECT_CHANGE == nCmd && 0x00 != sc && 0x00 == ascq)
+ {
+ finish.QuadPart -= start.QuadPart;
+
+ if (finish.QuadPart < freq.QuadPart && (finish.QuadPart*100000 / freq.QuadPart) < 200)
+ {
+ // test unit redy
+ INT i;
+ sc = 0x02; asc = 0x04; ascq = 0x01;
+ for (i = 0; i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x04 == asc && 0x01 == ascq; i++)
+ {
+ Sleep(50);
+ if (!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3) && ERROR_SEM_TIMEOUT == GetLastError())
+ i = MAX_TEST_ATTEMPT;
+ }
+ if (i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x3A ==asc)
+ {
+ DeviceIoControl(hDevice, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwOutput, NULL);
+ }
+ sc = 0x00;
+ }
+ }
+ }
+ CloseHandle(hDevice);
+ }
+ else bSuccess = FALSE;
+
+ if (!bSuccess)
+ { // we can try MCI
+
+ }
+ else if (0x00 != sc && !(0x02 == sc && 0x3A == asc))
+ {
+ SleepEx(200, TRUE);
+ QueueUserAPC(APC_Eject, GetCurrentThread(), param);
+ return;
+ }
+ }
+}
+
+static void CALLBACK APC_GetMCIInfo(ULONG_PTR param)
+{
+ CHAR cLetter;
+ MCI_OPEN_PARMS op = {0};
+ DM_MCI_PARAM *pmcip;
+
+ pmcip = (DM_MCI_PARAM*)param;
+ pmcip->header.opCode = DMOP_MCIINFO;
+ cLetter = CheckLetter(pmcip->header.cLetter);
+
+ pmcip->header.result = PRIMOSDK_CMDSEQUENCE;
+ if (cLetter)
+ {
+ wchar_t name[] = L"X:\\";
+ MCIDEVICEID devId;
+ MCI_INFO_PARMS ip = {0};
+ MCI_GENERIC_PARMS gp = {0};
+ MCI_STATUS_PARMS sp = {0};
+
+ name[0] = cLetter;
+
+ op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO;
+ op.lpstrElementName = name;
+
+ if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op))
+ {
+ WCHAR buffer[512] = {0};
+ INT nMaxTracks = pmcip->nTracks;
+
+ devId = op.wDeviceID;
+
+ if ((DMF_TRACKCOUNT | DMF_TRACKSINFO) & pmcip->header.fFlags)
+ {
+ sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
+ pmcip->nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1;
+ }
+ if (DMF_READY & pmcip->header.fFlags)
+ {
+ sp.dwItem = MCI_STATUS_READY;
+ pmcip->bReady = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
+ }
+ if (DMF_MODE & pmcip->header.fFlags)
+ {
+ sp.dwItem = MCI_STATUS_MODE;
+ pmcip->uMode = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (UINT)sp.dwReturn : 0;
+ }
+ if (DMF_MEDIUMPRESENT & pmcip->header.fFlags)
+ {
+ sp.dwItem = MCI_STATUS_MEDIA_PRESENT;
+ pmcip->bMediumPresent = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
+ }
+ if (DMF_MEDIUMUID & pmcip->header.fFlags)
+ {
+ ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t);
+ ip.lpstrReturn= buffer;
+ if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_IDENTITY, (DWORD_PTR)&ip))
+ {
+ INT len;
+ len = lstrlenW(ip.lpstrReturn);
+ if (S_OK == StringCchCopyW(pmcip->pszMediumUID, pmcip->cchMediumUID, ip.lpstrReturn))
+ {
+ pmcip->cchMediumUID = len;
+ }
+ else pmcip->cchMediumUID = 0 - (len + 1);
+ }
+ else pmcip->cchMediumUID = -1;
+ }
+ if (DMF_MEDIUMUPC & pmcip->header.fFlags)
+ {
+ ip.dwCallback = NULL;
+ ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t);
+ ip.lpstrReturn = buffer;
+ if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_UPC, (DWORD_PTR)&ip))
+ {
+ INT len;
+ len = lstrlenW(ip.lpstrReturn);
+ if (S_OK == StringCchCopyW(pmcip->pszMediumUPC, pmcip->cchMediumUPC, ip.lpstrReturn))
+ {
+ pmcip->cchMediumUPC = len;
+ }
+ else pmcip->cchMediumUPC = 0 - (len + 1);
+ }
+ else pmcip->cchMediumUPC = -1;
+ }
+
+ if (DMF_TRACKSINFO & pmcip->header.fFlags)
+ {
+ MCI_SET_PARMS setp;
+
+ if (nMaxTracks < pmcip->nTracks) pmcip->nTracks = (0 - pmcip->nTracks);
+ else
+ {
+ INT prevPos(0), length(0);
+ setp.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
+ mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp);
+
+ for (int i = pmcip->nTracks; i > 0; i--)
+ {
+ sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
+ sp.dwTrack = i;
+ mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
+ BOOL bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn);
+
+ sp.dwItem = MCI_STATUS_POSITION;
+ sp.dwTrack = i;
+ mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
+
+ if (i != pmcip->nTracks) length = prevPos - (INT)sp.dwReturn;
+ prevPos = (INT)sp.dwReturn;
+
+ if (i == pmcip->nTracks)
+ {
+ sp.dwItem = MCI_STATUS_LENGTH;
+ sp.dwTrack = i;
+ mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
+ length = (INT)sp.dwReturn;
+ }
+
+ pmcip->pTracks[i- 1] = (0x7FFFFFF & length) | ((bAudio) ? 0x80000000 : 0);
+ }
+
+ setp.dwTimeFormat = MCI_FORMAT_TMSF;
+ mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp);
+ }
+ }
+
+ mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp);
+ pmcip->header.result = PRIMOSDK_OK;
+ }
+ }
+
+ AsycOp_Complete(&pmcip->header);
+}
+
+static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param)
+{
+ CHAR cLetter;
+ BOOL bReady;
+ HRESULT hr(S_FALSE);
+ IDiscMaster *pdm;
+ IDiscRecorder *pdr;
+ IEnumDiscRecorders *per;
+ ULONG nActual;
+
+ wchar_t szDevName[] = L"X:\\";
+ wchar_t szTargetName[128] = {0};
+ DM_IMAPI_PARAM *pIMAPI;
+
+ pIMAPI = (DM_IMAPI_PARAM*)param;
+ cLetter = CheckLetter(pIMAPI->header.cLetter);
+
+ if (DriveManager_IsUnitReady(cLetter, &bReady) && !bReady)
+ {
+ SleepEx(1000, TRUE);
+ QueueUserAPC(APC_GetIMAPIInfo, GetCurrentThread(), param);
+ return;
+ }
+
+ pIMAPI->header.opCode = DMOP_IMAPIINFO;
+
+ pIMAPI->bRecorder = FALSE;
+ pIMAPI->header.result = (DWORD)E_INVALIDARG;
+
+ szDevName[0] = cLetter;
+ if (cLetter && QueryDosDeviceW(szDevName, szTargetName, sizeof(szTargetName)/sizeof(wchar_t)))
+ {
+ hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm);
+ if (SUCCEEDED(hr))
+ {
+ hr = pdm->Open();
+ if (SUCCEEDED(hr))
+ {
+ IEnumDiscMasterFormats *pef;
+ hr = pdm->EnumDiscMasterFormats(&pef);
+ if (SUCCEEDED(hr))
+ {
+ IID pFormats[2];
+ hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual);
+ if (SUCCEEDED(hr))
+ {
+ while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; }
+ if (nActual != ((ULONG)-1))
+ {
+ IRedbookDiscMaster *pdf;
+ hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf);
+ if (SUCCEEDED(hr))
+ {
+ pdf->Release();
+ hr = pdm->EnumDiscRecorders(&per);
+ if (SUCCEEDED(hr))
+ {
+ while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0)
+ {
+ BSTR bstrPath;
+ hr = pdr->GetPath(&bstrPath);
+ if (SUCCEEDED(hr))
+ {
+ if (0 == lstrcmp(szTargetName, bstrPath))
+ {
+ pIMAPI->bRecorder = TRUE;
+ if ((DMF_BASEPNPID & pIMAPI->header.fFlags) && FAILED(pdr->GetBasePnPID(&pIMAPI->bstrBasePnPID))) pIMAPI->bstrBasePnPID = NULL;
+ if ((DMF_DISPLAYNAMES & pIMAPI->header.fFlags) && FAILED(pdr->GetDisplayNames(&pIMAPI->bstrVendorID, &pIMAPI->bstrProductID, &pIMAPI->bstrRevision)))
+ {
+ pIMAPI->bstrVendorID = NULL;
+ pIMAPI->bstrProductID = NULL;
+ pIMAPI->bstrRevision = NULL;
+ }
+ if (DMF_PATH & pIMAPI->header.fFlags)
+ {
+ pIMAPI->bstrPath = bstrPath;
+ bstrPath = NULL;
+ }
+ if ((DMF_DRIVESTATE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderState(&pIMAPI->ulDriveState))) pIMAPI->ulDriveState = (ULONG)-1;
+ if ((DMF_DRIVETYPE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderType(&pIMAPI->fDriveType))) pIMAPI->fDriveType = 0;
+ if ((DMF_QUERYMEDIATYPE | DMF_QUERYMEDIAINFO) & pIMAPI->header.fFlags)
+ {
+ BOOL bTypeOk(FALSE), bInfoOk(FALSE);
+ if (SUCCEEDED(pdr->OpenExclusive()))
+ {
+ if (0 == (DMF_QUERYMEDIATYPE & pIMAPI->header.fFlags) ||
+ SUCCEEDED(pdr->QueryMediaType(&pIMAPI->fMediaType, &pIMAPI->fMediaFlags))) bTypeOk = TRUE;
+ if (0 == (DMF_QUERYMEDIAINFO & pIMAPI->header.fFlags) ||
+ SUCCEEDED(pdr->QueryMediaInfo(&pIMAPI->bSessions, &pIMAPI->bLastTrack, &pIMAPI->ulStartAddress,
+ &pIMAPI->ulNextWritable, &pIMAPI->ulFreeBlocks))) bInfoOk = TRUE;
+ pdr->Close();
+ }
+
+
+ if (!bTypeOk)
+ {
+ pIMAPI->fMediaType = -1;
+ pIMAPI->fMediaFlags = -1;
+ }
+ if (!bInfoOk)
+ {
+ pIMAPI->bLastTrack = 0;
+ pIMAPI->bSessions = 0;
+ pIMAPI->ulFreeBlocks = 0;
+ pIMAPI->ulNextWritable = 0;
+ pIMAPI->ulStartAddress = 0;
+ }
+
+
+ }
+ break;
+ }
+ if (bstrPath) SysFreeString(bstrPath);
+ }
+ pdr->Release();
+ }
+ per->Release();
+ }
+ }
+ }
+ }
+ pef->Release();
+ }
+ pdm->Close();
+ }
+ pdm->Release();
+ }
+ }
+ pIMAPI->header.result = hr;
+ AsycOp_Complete(&pIMAPI->header);
+} \ No newline at end of file