drivemngr.cpp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910
  1. #include "main.h"
  2. #include "./drivemngr.h"
  3. #include "./primosdk_helper.h"
  4. #include "./resource.h"
  5. #include "../nu/trace.h"
  6. #include "./dbt.h"
  7. #include "./spti.h"
  8. #include <setupapi.h>
  9. #include <imapi.h>
  10. #include <strsafe.h>
  11. #define LISTENER_CLASSNAME L"MLDISCLISTENER"
  12. #define LISTENER_WINDOWNAME L""
  13. #define POLLMEDIUMCHANGE_INTERVAL 2000
  14. #define POLLMEDIUMVALIDATE_INTERVAL 6000
  15. #define DMS_SUSPENDED 0x0000
  16. #define DMS_ACTIVE 0x0001
  17. #define WM_EX_QUIT (WM_APP + 1)
  18. typedef struct _MEDIUMINFO_I
  19. {
  20. UINT msLastPolled; // last time medium info was polled
  21. UINT serialNumber; // medium serialnumber
  22. } MEDIUMINFO_I;
  23. typedef struct _DRIVEINFO_I
  24. {
  25. char cLetter; // drive letter
  26. INT deviceNumber; // system assigned device number (unique till next reboot)
  27. BOOL bMediumInserted; // if TRUE mediumInfo contains valid data
  28. CHAR cMode; // drive mode
  29. DWORD dwType; // drive type
  30. LPWSTR pszDevName; // device name
  31. HANDLE hThread; // device info thread
  32. DWORD dwThreadId;
  33. MEDIUMINFO_I mediumInfo;
  34. } DRIVEINFO_I;
  35. typedef struct _DRIVEMNGR
  36. {
  37. HWND hwndListener;
  38. DMNPROC callback;
  39. UINT fState;
  40. CRITICAL_SECTION csLock;
  41. DRIVEINFO_I *pDrives;
  42. INT nCount;
  43. INT nAlloc;
  44. HANDLE hPollingThread;
  45. DWORD dwPollingThread;
  46. } DRIVEMNGR;
  47. typedef struct _DEVICEINFO
  48. {
  49. CHAR cLetter;
  50. LPWSTR pszDevName;
  51. WCHAR szTargetPath[128];
  52. WCHAR szVolumeName[64];
  53. DWORD dwType;
  54. INT deviceNumber;
  55. INT opCode;
  56. } DEVICEINFO;
  57. static DRIVEMNGR *pMngr = NULL;
  58. static void CALLBACK APC_CheckDrives(ULONG_PTR param);
  59. static void CALLBACK APC_IsMediumChanged(ULONG_PTR param);
  60. static void CALLBACK APC_GetUnitInfo(ULONG_PTR param);
  61. static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param);
  62. static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param);
  63. static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param);
  64. static void CALLBACK APC_GetTitle(ULONG_PTR param);
  65. static void CALLBACK APC_DriveScan(ULONG_PTR param);
  66. static void CALLBACK APC_GetMCIInfo(ULONG_PTR param);
  67. static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param);
  68. static void CALLBACK APC_Eject(ULONG_PTR param);
  69. static DWORD CALLBACK InfoThread(LPVOID param);
  70. static DWORD CALLBACK PollingThread(LPVOID param);
  71. static void CALLBACK PollMediumInfo(ULONG_PTR param);
  72. static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  73. static CHAR CheckLetter(CHAR cLetter)
  74. {
  75. if (cLetter < 'A' || cLetter > 'Z')
  76. {
  77. if (cLetter >= 'a' && cLetter <= 'z') return (cLetter - 0x20);
  78. return 0;
  79. }
  80. return cLetter;
  81. }
  82. static LPCWSTR GetDeviceName(CHAR cLetter)
  83. {
  84. LPCWSTR pszDevName;
  85. if (!pMngr) return NULL;
  86. pszDevName = NULL;
  87. EnterCriticalSection(&pMngr->csLock);
  88. for (int i = 0; i < pMngr->nCount; i++)
  89. {
  90. if (pMngr->pDrives[i].cLetter == cLetter)
  91. {
  92. pszDevName = pMngr->pDrives[i].pszDevName;
  93. break;
  94. }
  95. }
  96. LeaveCriticalSection(&pMngr->csLock);
  97. return pszDevName;
  98. }
  99. static BOOL IsPollingRequired(void)
  100. {
  101. HKEY hKey;
  102. LONG result;
  103. BOOL bAutoRunEnabled;
  104. bAutoRunEnabled = FALSE;
  105. result = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Cdrom"), &hKey);
  106. if (ERROR_SUCCESS == result)
  107. {
  108. DWORD value;
  109. DWORD size;
  110. size = sizeof(DWORD);
  111. result = RegQueryValueEx(hKey, TEXT("AutoRun"), NULL, NULL, (LPBYTE)&value, &size);
  112. if (ERROR_SUCCESS == result) bAutoRunEnabled = (0 != value);
  113. RegCloseKey(hKey);
  114. }
  115. return !bAutoRunEnabled;
  116. }
  117. static CHAR Drive_LetterFromMask(ULONG unitmask)
  118. {
  119. char i;
  120. for (i = 0; i < 26; ++i)
  121. {
  122. if (unitmask & 0x1) break;
  123. unitmask = unitmask >> 1;
  124. }
  125. return (i + 'A');
  126. }
  127. static BOOL Drive_Add(DEVICEINFO *pDevInfo)
  128. {
  129. DRIVEINFO_I *pDrive;
  130. if (!pMngr) return FALSE;
  131. EnterCriticalSection(&pMngr->csLock);
  132. INT index, opCode;
  133. opCode = 0;
  134. for (index = 0; index < pMngr->nCount && pMngr->pDrives[index].cLetter != pDevInfo->cLetter; index++);
  135. if (index != pMngr->nCount)
  136. {
  137. pDrive = &pMngr->pDrives[index];
  138. if (pDrive->deviceNumber != pDevInfo->deviceNumber || pDrive->dwType != pDevInfo->dwType) opCode = 1;
  139. }
  140. else
  141. {
  142. if (pMngr->nCount == pMngr->nAlloc)
  143. {
  144. LPVOID data;
  145. data = realloc(pMngr->pDrives, sizeof(DRIVEINFO_I)*(pMngr->nCount + 2));
  146. if (!data)
  147. {
  148. LeaveCriticalSection(&pMngr->csLock);
  149. return FALSE;
  150. }
  151. pMngr->pDrives = (DRIVEINFO_I*)data;
  152. pMngr->nAlloc += 2;
  153. }
  154. pDrive = &pMngr->pDrives[pMngr->nCount];
  155. pMngr->nCount++;
  156. ZeroMemory(pDrive, sizeof(DRIVEINFO_I));
  157. pDrive->cLetter = pDevInfo->cLetter;
  158. opCode = 2;
  159. }
  160. if (opCode)
  161. {
  162. pDrive->deviceNumber = pDevInfo->deviceNumber;
  163. pDrive->dwType = pDevInfo->dwType;
  164. if (pDrive->pszDevName) free(pDrive->pszDevName);
  165. pDrive->pszDevName = _wcsdup(pDevInfo->pszDevName);
  166. }
  167. LeaveCriticalSection(&pMngr->csLock);
  168. if (opCode && pMngr->callback) pMngr->callback((2 == opCode) ? DMW_DRIVEADDED : DMW_DRIVECHANGED, pDevInfo->cLetter);
  169. return TRUE;
  170. }
  171. static BOOL Drive_Remove(CHAR cLetter)
  172. {
  173. INT index;
  174. BOOL bReportChanges;
  175. if (!pMngr) return FALSE;
  176. EnterCriticalSection(&pMngr->csLock);
  177. bReportChanges = FALSE;
  178. index = pMngr->nCount;
  179. while (index-- && pMngr->pDrives[index].cLetter != cLetter);
  180. if (-1 != index)
  181. {
  182. if (pMngr->pDrives[index].pszDevName) free(pMngr->pDrives[index].pszDevName);
  183. if (index != pMngr->nCount - 1) MoveMemory(&pMngr->pDrives[index], &pMngr->pDrives[index + 1], sizeof(DRIVEINFO_I)*(pMngr->nCount - index));
  184. pMngr->nCount--;
  185. bReportChanges = TRUE;
  186. }
  187. LeaveCriticalSection(&pMngr->csLock);
  188. if (bReportChanges && pMngr->callback) pMngr->callback(DMW_DRIVEREMOVED, cLetter);
  189. return TRUE;
  190. }
  191. static HRESULT QueueInfoAPC(CHAR cLetter, PAPCFUNC pfnAPC, ULONG_PTR param)
  192. {
  193. DWORD *pdwThreadId(NULL);
  194. HRESULT hr(S_FALSE);
  195. HANDLE *phThread(NULL);
  196. static HANDLE hDrivesInfoThread = NULL;
  197. if (NULL == pMngr) return E_FAIL;
  198. EnterCriticalSection(&pMngr->csLock);
  199. if (cLetter)
  200. {
  201. INT index = pMngr->nCount;
  202. while (index-- && pMngr->pDrives[index].cLetter != cLetter);
  203. if (-1 != index)
  204. {
  205. phThread = &pMngr->pDrives[index].hThread;
  206. pdwThreadId = &pMngr->pDrives[index].dwThreadId;
  207. }
  208. }
  209. else
  210. {
  211. phThread = &hDrivesInfoThread;
  212. }
  213. if (phThread)
  214. {
  215. if (!*phThread)
  216. {
  217. DWORD tid;
  218. *phThread = CreateThread(NULL, 0, InfoThread, NULL, 0, &tid);
  219. if (pdwThreadId) *pdwThreadId = tid;
  220. Sleep(100);
  221. }
  222. if (*phThread)
  223. {
  224. if (0 == QueueUserAPC(pfnAPC, *phThread, param))
  225. {
  226. TRACE_LINE(TEXT("queue user apc failed"));
  227. }
  228. else hr = S_OK;
  229. }
  230. }
  231. LeaveCriticalSection(&pMngr->csLock);
  232. return hr;
  233. }
  234. static BOOL Medium_Add(CHAR cLetter, DWORD serial)
  235. {
  236. INT index;
  237. if (!pMngr) return FALSE;
  238. EnterCriticalSection(&pMngr->csLock);
  239. index = pMngr->nCount;
  240. while (index-- && pMngr->pDrives[index].cLetter != cLetter);
  241. if (-1 != index)
  242. {
  243. pMngr->pDrives[index].bMediumInserted = TRUE;
  244. pMngr->pDrives[index].mediumInfo.msLastPolled = 0;
  245. pMngr->pDrives[index].mediumInfo.serialNumber = serial;
  246. }
  247. LeaveCriticalSection(&pMngr->csLock);
  248. if (-1 != index)
  249. {
  250. if (-1 == serial) QueueInfoAPC(cLetter, APC_IsMediumChanged, (ULONG_PTR)cLetter);
  251. if (pMngr->callback) pMngr->callback(DMW_MEDIUMARRIVED, cLetter);
  252. }
  253. return TRUE;
  254. }
  255. static BOOL Medium_Remove(CHAR cLetter)
  256. {
  257. INT index;
  258. if (!pMngr) return FALSE;
  259. EnterCriticalSection(&pMngr->csLock);
  260. index = pMngr->nCount;
  261. while (index-- && pMngr->pDrives[index].cLetter != cLetter);
  262. if (-1 != index) pMngr->pDrives[index].bMediumInserted = FALSE;
  263. LeaveCriticalSection(&pMngr->csLock);
  264. if (-1 != index && pMngr->callback) pMngr->callback(DMW_MEDIUMREMOVED, cLetter);
  265. return TRUE;
  266. }
  267. BOOL DriveManager_Initialize(DMNPROC DMNProc, BOOL bSuspended)
  268. {
  269. WNDCLASSW wc = {0};
  270. HINSTANCE hInstance;
  271. if (pMngr || !DMNProc) return FALSE;
  272. pMngr = (DRIVEMNGR*)calloc(1, sizeof(DRIVEMNGR));
  273. if (!pMngr) return FALSE;
  274. hInstance = GetModuleHandle(NULL);
  275. if (!GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc))
  276. {
  277. wc.hInstance = hInstance;
  278. wc.lpfnWndProc = ListenerWndProc;
  279. wc.lpszClassName = LISTENER_CLASSNAME;
  280. if (!RegisterClassW(&wc))
  281. {
  282. DriveManager_Uninitialize(0);
  283. return FALSE;
  284. }
  285. }
  286. pMngr->hwndListener = CreateWindowW(LISTENER_CLASSNAME, LISTENER_WINDOWNAME, WS_DISABLED, 0,0,0,0, HWND_DESKTOP, NULL, hInstance, 0L);
  287. if (!pMngr->hwndListener)
  288. {
  289. DriveManager_Uninitialize(0);
  290. return FALSE;
  291. }
  292. InitializeCriticalSection(&pMngr->csLock);
  293. pMngr->callback = DMNProc;
  294. return TRUE;
  295. }
  296. BOOL DriveManager_Uninitialize(INT msExitWaitTime)
  297. {
  298. if (pMngr)
  299. {
  300. WNDCLASSW wc;
  301. HINSTANCE hInstance;
  302. if (pMngr->hwndListener) DestroyWindow(pMngr->hwndListener);
  303. hInstance = GetModuleHandle(NULL);
  304. if (GetClassInfoW(hInstance, LISTENER_CLASSNAME, &wc)) UnregisterClassW(LISTENER_CLASSNAME, hInstance);
  305. EnterCriticalSection(&pMngr->csLock);
  306. for (int index =0; index < pMngr->nCount; index++)
  307. {
  308. if (pMngr->pDrives[index].hThread)
  309. {
  310. PostThreadMessage(pMngr->pDrives[index].dwThreadId, WM_EX_QUIT, 1, 0);
  311. INT result = WaitForSingleObject(pMngr->pDrives[index].hThread, msExitWaitTime);
  312. if (WAIT_TIMEOUT == result) TerminateThread(pMngr->pDrives[index].hThread, 1);
  313. CloseHandle(pMngr->pDrives[index].hThread);
  314. pMngr->pDrives[index].hThread = NULL;
  315. }
  316. }
  317. LeaveCriticalSection(&pMngr->csLock);
  318. if (pMngr->hPollingThread)
  319. {
  320. PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0);
  321. INT result = WaitForSingleObject(pMngr->hPollingThread, msExitWaitTime);
  322. if (WAIT_TIMEOUT == result) TerminateThread(pMngr->hPollingThread, 1);
  323. CloseHandle(pMngr->hPollingThread);
  324. pMngr->hPollingThread = NULL;
  325. }
  326. EnterCriticalSection(&pMngr->csLock);
  327. if (pMngr->pDrives)
  328. {
  329. free(pMngr->pDrives);
  330. }
  331. DRIVEMNGR *managerInstance = pMngr;
  332. pMngr = NULL;
  333. LeaveCriticalSection(&managerInstance->csLock);
  334. DeleteCriticalSection(&managerInstance->csLock);
  335. free(managerInstance);
  336. PrimoSDKHelper_Uninitialize();
  337. }
  338. return TRUE;
  339. }
  340. BOOL DriveManager_Suspend(void)
  341. {
  342. if (!pMngr) return FALSE;
  343. pMngr->fState = DMS_SUSPENDED;
  344. if (pMngr->hPollingThread)
  345. {
  346. PostThreadMessage(pMngr->dwPollingThread, WM_EX_QUIT, 1, 0);
  347. pMngr->hPollingThread = NULL;
  348. }
  349. return TRUE;
  350. }
  351. BOOL DriveManager_Update(BOOL bAsync)
  352. {
  353. if (bAsync) return (QueueInfoAPC(0, APC_DriveScan, 0) && QueueInfoAPC(0, PollMediumInfo, 0));
  354. else
  355. {
  356. APC_DriveScan(0);
  357. QueueInfoAPC(0, PollMediumInfo, 0);
  358. }
  359. return TRUE;
  360. }
  361. BOOL DriveManager_Resume(BOOL bUpdate)
  362. {
  363. if (!pMngr) return FALSE;
  364. pMngr->fState = DMS_ACTIVE;
  365. EnterCriticalSection(&pMngr->csLock);
  366. for (int index =0; index < pMngr->nCount; index++) pMngr->pDrives[index].mediumInfo.msLastPolled = 0;
  367. LeaveCriticalSection(&pMngr->csLock);
  368. APC_DriveScan(0);
  369. QueueInfoAPC(0, PollMediumInfo, 0);
  370. if (NULL == pMngr->hPollingThread && IsPollingRequired())
  371. {
  372. pMngr->hPollingThread = CreateThread(NULL, 0, PollingThread, NULL, 0, &pMngr->dwPollingThread);
  373. }
  374. return TRUE;
  375. }
  376. BOOL DriveManager_SetDriveMode(CHAR cLetter, CHAR cMode)
  377. {
  378. BOOL report;
  379. INT index;
  380. index = -1;
  381. report = FALSE;
  382. cLetter = CheckLetter(cLetter);
  383. if (pMngr && cLetter)
  384. {
  385. EnterCriticalSection(&pMngr->csLock);
  386. for (index =0; index < pMngr->nCount; index++)
  387. {
  388. if (pMngr->pDrives[index].cLetter == cLetter)
  389. {
  390. if (pMngr->pDrives[index].cMode != cMode)
  391. {
  392. pMngr->pDrives[index].cMode = cMode;
  393. report = TRUE;
  394. }
  395. break;
  396. }
  397. }
  398. if (index == pMngr->nCount) index = -1;
  399. LeaveCriticalSection(&pMngr->csLock);
  400. if (report && pMngr->callback) pMngr->callback(DMW_MODECHANGED, MAKEWORD(cLetter, cMode));
  401. }
  402. return (-1 != index);
  403. }
  404. CHAR DriveManager_GetDriveMode(CHAR cLetter)
  405. {
  406. CHAR result;
  407. result = DM_MODE_ERROR;
  408. cLetter = CheckLetter(cLetter);
  409. if (pMngr && cLetter)
  410. {
  411. INT index;
  412. EnterCriticalSection(&pMngr->csLock);
  413. for (index =0; index < pMngr->nCount; index++)
  414. {
  415. if (pMngr->pDrives[index].cLetter == cLetter)
  416. {
  417. result = pMngr->pDrives[index].cMode;
  418. break;
  419. }
  420. }
  421. LeaveCriticalSection(&pMngr->csLock);
  422. }
  423. return result;
  424. }
  425. DWORD DriveManager_GetDriveType(CHAR cLetter)
  426. {
  427. DWORD type;
  428. type = DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN;
  429. cLetter = CheckLetter(cLetter);
  430. if (pMngr && cLetter)
  431. {
  432. INT index;
  433. EnterCriticalSection(&pMngr->csLock);
  434. for (index =0; index < pMngr->nCount; index++)
  435. {
  436. if (pMngr->pDrives[index].cLetter == cLetter)
  437. {
  438. type = pMngr->pDrives[index].dwType;
  439. break;
  440. }
  441. }
  442. LeaveCriticalSection(&pMngr->csLock);
  443. }
  444. return type;
  445. }
  446. BOOL DriveManager_IsMediumInserted(CHAR cLetter)
  447. {
  448. BOOL result;
  449. result = FALSE;
  450. cLetter = CheckLetter(cLetter);
  451. if (pMngr && cLetter)
  452. {
  453. INT index;
  454. EnterCriticalSection(&pMngr->csLock);
  455. for (index =0; index < pMngr->nCount; index++)
  456. {
  457. if (pMngr->pDrives[index].cLetter == cLetter)
  458. {
  459. result = pMngr->pDrives[index].bMediumInserted;
  460. break;
  461. }
  462. }
  463. LeaveCriticalSection(&pMngr->csLock);
  464. }
  465. return result;
  466. }
  467. INT DriveManager_GetDriveList(CHAR *pLetters, INT cchSize)
  468. {
  469. INT r = 0;
  470. if (!pLetters || !pMngr) return -1;
  471. EnterCriticalSection(&pMngr->csLock);
  472. for (int index =0; index < pMngr->nCount; index++)
  473. {
  474. *pLetters = pMngr->pDrives[index].cLetter;
  475. pLetters++;
  476. cchSize--;
  477. r++;
  478. if (0 == cchSize) break;
  479. }
  480. LeaveCriticalSection(&pMngr->csLock);
  481. return r;
  482. }
  483. static BOOL QueueInfoJob(PAPCFUNC pfnAPC, DM_NOTIFY_PARAM *pHeader)
  484. {
  485. BOOL result(TRUE);
  486. if (!pMngr || !pHeader) result = FALSE;
  487. if (result)
  488. {
  489. HANDLE hProc = GetCurrentProcess();
  490. pHeader->hReserved = 0;
  491. result = (BOOL)DuplicateHandle(hProc, GetCurrentThread(), hProc, &pHeader->hReserved,
  492. 0, FALSE, DUPLICATE_SAME_ACCESS);
  493. if (!result) pHeader->hReserved = 0;
  494. }
  495. if (result)
  496. {
  497. CHAR cLetter = CheckLetter(pHeader->cLetter);
  498. result = (cLetter && S_OK == QueueInfoAPC(cLetter, pfnAPC, (ULONG_PTR)pHeader));
  499. }
  500. if(!result && pHeader && pHeader->fnFree)
  501. {
  502. if (pHeader->hReserved) CloseHandle(pHeader->hReserved);
  503. pHeader->fnFree(pHeader);
  504. }
  505. return result;
  506. }
  507. BOOL DriveManager_GetUnitInfo(DM_UNITINFO_PARAM *puip)
  508. {
  509. return QueueInfoJob(APC_GetUnitInfo, (DM_NOTIFY_PARAM*)puip);
  510. }
  511. BOOL DriveManager_GetUnitInfo2(DM_UNITINFO2_PARAM *puip)
  512. {
  513. return QueueInfoJob(APC_GetUnitInfo2, (DM_NOTIFY_PARAM*)puip);
  514. }
  515. BOOL DriveManager_GetDiscInfoEx(DM_DISCINFOEX_PARAM *pdip)
  516. {
  517. return QueueInfoJob(APC_GetDiscInfoEx, (DM_NOTIFY_PARAM*)pdip);
  518. }
  519. BOOL DriveManager_GetDiscInfo2(DM_DISCINFO2_PARAM *pdip)
  520. {
  521. return QueueInfoJob(APC_GetDiscInfo2, (DM_NOTIFY_PARAM*)pdip);
  522. }
  523. BOOL DriveManager_QueryTitle(DM_TITLE_PARAM *pdtp)
  524. {
  525. return QueueInfoJob(APC_GetTitle, (DM_NOTIFY_PARAM*)pdtp);
  526. }
  527. BOOL DriveManager_GetMCIInfo(DM_MCI_PARAM *pmcip)
  528. {
  529. return QueueInfoJob(APC_GetMCIInfo, (DM_NOTIFY_PARAM*)pmcip);
  530. }
  531. BOOL DriveManager_GetIMAPIInfo(DM_IMAPI_PARAM *pIMAPI)
  532. {
  533. return QueueInfoJob(APC_GetIMAPIInfo, (DM_NOTIFY_PARAM*)pIMAPI);
  534. }
  535. BOOL DriveManager_Eject(CHAR cLetter, INT nCmd)
  536. {
  537. if (!pMngr) return FALSE;
  538. CHAR cLetter1 = CheckLetter(cLetter);
  539. return (cLetter1 && QueueInfoAPC(cLetter1, APC_Eject, (ULONG_PTR)MAKELONG(cLetter, nCmd)));
  540. }
  541. BOOL DriveManager_IsUnitReady(CHAR cLetter, BOOL *pbReady)
  542. {
  543. BYTE sc, asc, ascq;
  544. BOOL bSuccess;
  545. HANDLE hDevice;
  546. *pbReady = FALSE;
  547. hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE,
  548. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  549. if (INVALID_HANDLE_VALUE == hDevice) return FALSE;
  550. bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3);
  551. if (!bSuccess)
  552. {
  553. if (ERROR_SEM_TIMEOUT == GetLastError()) bSuccess = TRUE;
  554. }
  555. else if (0x00 == sc || (0x02 == sc && 0x3A == asc)) *pbReady = TRUE;
  556. CloseHandle(hDevice);
  557. return bSuccess;
  558. }
  559. static BOOL GetVolumeNameForVolumeMountPoint_DL(LPCWSTR lpszVolumeMountPoint, LPWSTR lpszVolumeName, DWORD cchBufferLength)
  560. {
  561. static BOOL (WINAPI *func)(LPCWSTR, LPWSTR, DWORD) = NULL;
  562. if (!func)
  563. {
  564. UINT prevErrorMode;
  565. HMODULE hModule;
  566. prevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  567. hModule = LoadLibraryW(L"Kernel32.dll");
  568. SetErrorMode(prevErrorMode);
  569. if (hModule)
  570. {
  571. func = (BOOL (WINAPI*)(LPCWSTR, LPWSTR, DWORD))GetProcAddress(hModule, "GetVolumeNameForVolumeMountPointW");
  572. FreeLibrary(hModule);
  573. }
  574. }
  575. return (func) ? func(lpszVolumeMountPoint, lpszVolumeName, cchBufferLength) : FALSE;
  576. }
  577. static DWORD GetDeviceNames(DEVICEINFO *pDevInfo, INT count)
  578. {
  579. HANDLE hDevInfo;
  580. SP_DEVICE_INTERFACE_DATA spiData;
  581. SP_DEVICE_INTERFACE_DETAIL_DATA_W *pspiDetailData;
  582. DWORD dwErrorCode, dwReqSize, dwDetailSize;
  583. wchar_t volume[128], szDosName[] = L"X:\\", szDosName1[] = L"X:\\";
  584. if (!pDevInfo || !count) return ERROR_INVALID_DATA;
  585. for (int i = 0; i < count; i++)
  586. {
  587. szDosName[0] = pDevInfo[i].cLetter;
  588. GetVolumeNameForVolumeMountPoint_DL(szDosName, pDevInfo[i].szVolumeName, sizeof(pDevInfo[i].szVolumeName)/sizeof(wchar_t));
  589. szDosName1[0] = pDevInfo[i].cLetter;
  590. QueryDosDeviceW(szDosName1, pDevInfo[i].szTargetPath, sizeof(pDevInfo[i].szTargetPath)/sizeof(wchar_t));
  591. }
  592. hDevInfo = SetupDiGetClassDevs((LPGUID)&CdRomClassGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_INTERFACEDEVICE));
  593. if (INVALID_HANDLE_VALUE == hDevInfo) return GetLastError();
  594. dwDetailSize = 0;
  595. pspiDetailData = NULL;
  596. spiData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  597. dwErrorCode = 0;
  598. for (int index = 0; !dwErrorCode; index++)
  599. {
  600. BOOL bResult = SetupDiEnumDeviceInterfaces(hDevInfo, 0, (LPGUID)&CdRomClassGuid, index, &spiData);
  601. if (!bResult)
  602. {
  603. dwErrorCode = GetLastError();
  604. break;
  605. }
  606. bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, NULL, 0, &dwReqSize, NULL);
  607. if (!bResult)
  608. {
  609. dwErrorCode = GetLastError();
  610. if (ERROR_INSUFFICIENT_BUFFER != dwErrorCode) break;
  611. dwErrorCode = 0;
  612. }
  613. dwReqSize += 2*sizeof(wchar_t);
  614. if (dwReqSize > dwDetailSize)
  615. {
  616. LPVOID data;
  617. data = realloc(pspiDetailData, dwReqSize);
  618. if (!data) { dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; break; }
  619. pspiDetailData = (SP_DEVICE_INTERFACE_DETAIL_DATA*)data;
  620. dwDetailSize = dwReqSize;
  621. }
  622. pspiDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  623. bResult = SetupDiGetDeviceInterfaceDetailW(hDevInfo, &spiData, pspiDetailData, dwDetailSize, NULL, NULL);
  624. if (!bResult)
  625. {
  626. dwErrorCode = GetLastError();
  627. break;
  628. }
  629. INT cchName;
  630. cchName = lstrlenW(pspiDetailData->DevicePath);
  631. pspiDetailData->DevicePath[cchName] = L'\\';
  632. pspiDetailData->DevicePath[cchName + 1] = 0x00;
  633. if(GetVolumeNameForVolumeMountPoint_DL(pspiDetailData->DevicePath, volume, sizeof(volume)/sizeof(wchar_t)))
  634. {
  635. for (int i = 0; i < count; i++)
  636. {
  637. if (!pDevInfo[i].pszDevName && 0 == lstrcmpW(volume, pDevInfo[i].szVolumeName))
  638. {
  639. pDevInfo[i].pszDevName = (LPWSTR)calloc((cchName + 1), sizeof(wchar_t));
  640. if (pDevInfo[i].pszDevName) StringCchCopyNW(pDevInfo[i].pszDevName, cchName + 1, pspiDetailData->DevicePath, cchName);
  641. break;
  642. }
  643. }
  644. }
  645. }
  646. if (pspiDetailData) free(pspiDetailData);
  647. SetupDiDestroyDeviceInfoList(hDevInfo);
  648. for (int i = 0; i < count; i++)
  649. {
  650. if (!pDevInfo[i].pszDevName)
  651. {
  652. wchar_t szDevName[] = L"\\\\.\\x:";
  653. szDevName[4] = pDevInfo[i].cLetter;
  654. pDevInfo[i].pszDevName = (LPWSTR)calloc(sizeof(szDevName) + 2, sizeof(wchar_t));
  655. if (pDevInfo[i].pszDevName) StringCbCopyW(pDevInfo[i].pszDevName, sizeof(szDevName) + 2, szDevName);
  656. }
  657. }
  658. return dwErrorCode;
  659. }
  660. static void GetDeviceCaps(DEVICEINFO *pDevInfo, INT count)
  661. {
  662. for( int i = 0; i < count; i++)
  663. {
  664. pDevInfo[i].dwType = ((pDevInfo[i].dwType & 0x0000FFFF) | DRIVE_CAP_UNKNOWN);
  665. }
  666. // TODO come back to this later on, but for the moment not seeing any noticeable issues
  667. // with disabling this and instead and instead it helps prevent random trk****.tmp
  668. // files being generated and also seems to fix the crash on start people have here
  669. /*IDiscMaster *pdm;
  670. IDiscRecorder *pdr;
  671. IEnumDiscRecorders *per;
  672. ULONG nActual;
  673. HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm);
  674. if (SUCCEEDED(hr))
  675. {
  676. // TODO determine why this is causing trk*.tmp files to be created when called
  677. // which ends up spamming the %temp% folder everytime Winamp starts :o(
  678. hr = pdm->Open();
  679. if (SUCCEEDED(hr))
  680. {
  681. IEnumDiscMasterFormats *pef;
  682. hr = pdm->EnumDiscMasterFormats(&pef);
  683. if (SUCCEEDED(hr))
  684. {
  685. IID pFormats[2];
  686. hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual);
  687. if (SUCCEEDED(hr))
  688. {
  689. while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; }
  690. if (nActual != ((ULONG)-1))
  691. {
  692. IRedbookDiscMaster *pdf;
  693. hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf);
  694. if (SUCCEEDED(hr))
  695. {
  696. pdf->Release();
  697. hr = pdm->EnumDiscRecorders(&per);
  698. if (SUCCEEDED(hr))
  699. {
  700. while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0)
  701. {
  702. BSTR bstrPath;
  703. hr = pdr->GetPath(&bstrPath);
  704. if (SUCCEEDED(hr))
  705. {
  706. for (int i = 0; i < count; i++)
  707. {
  708. if (0 == lstrcmpW(pDevInfo[i].szTargetPath, bstrPath))
  709. {
  710. LONG type;
  711. if (SUCCEEDED(pdr->GetRecorderType(&type)))
  712. {
  713. pDevInfo[i].dwType &= 0x0000FFFF;
  714. switch(type)
  715. {
  716. case RECORDER_CDR: pDevInfo[i].dwType |= DRIVE_CAP_R; break;
  717. case RECORDER_CDRW: pDevInfo[i].dwType |= DRIVE_CAP_RW; break;
  718. }
  719. }
  720. break;
  721. }
  722. }
  723. if (bstrPath) SysFreeString(bstrPath);
  724. }
  725. pdr->Release();
  726. }
  727. per->Release();
  728. }
  729. }
  730. }
  731. }
  732. pef->Release();
  733. }
  734. pdm->Close();
  735. }
  736. pdm->Release();
  737. }
  738. else
  739. {
  740. }*/
  741. }
  742. static void Listener_OnDeviceChange(HWND hwnd, UINT nType, DWORD_PTR dwData)
  743. {
  744. DEV_BROADCAST_HDR *phdr;
  745. switch(nType)
  746. {
  747. case DBT_DEVICEARRIVAL:
  748. phdr = (DEV_BROADCAST_HDR*)dwData;
  749. if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype)
  750. {
  751. DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr;
  752. if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Add(Drive_LetterFromMask(pvol->dbcv_unitmask), (DWORD)-1);
  753. else if (0 == pvol->dbcv_flags)
  754. {
  755. char root[] = "X:\\";
  756. root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask);
  757. if (DRIVE_CDROM == GetDriveTypeA(root)) QueueInfoAPC(0, APC_CheckDrives, (ULONG_PTR)root[0]);
  758. }
  759. }
  760. break;
  761. case DBT_DEVICEREMOVECOMPLETE:
  762. phdr = (DEV_BROADCAST_HDR*)dwData;
  763. if (DBT_DEVTYP_VOLUME == phdr->dbch_devicetype)
  764. {
  765. DEV_BROADCAST_VOLUME *pvol = (DEV_BROADCAST_VOLUME*)phdr;
  766. if (DBTF_MEDIA == pvol->dbcv_flags) Medium_Remove(Drive_LetterFromMask(pvol->dbcv_unitmask));
  767. else if (0 == pvol->dbcv_flags)
  768. {
  769. char root[] = "X:\\";
  770. root[0] = Drive_LetterFromMask(pvol->dbcv_unitmask);
  771. if (DRIVE_CDROM == GetDriveTypeA(root)) Drive_Remove(root[0]);
  772. }
  773. }
  774. break;
  775. }
  776. }
  777. static DWORD CALLBACK InfoThread(LPVOID param)
  778. {
  779. MSG msg;
  780. DWORD start, status, timeout, result(0);
  781. BOOL bComInit, run(TRUE);
  782. HANDLE hTemp(NULL);
  783. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  784. bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
  785. timeout = 20000; // 20 seconds delay
  786. start = GetTickCount();
  787. while(run)
  788. {
  789. DWORD elapsed = GetTickCount() - start;
  790. if (elapsed < timeout)
  791. status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed,
  792. QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
  793. else status = WAIT_TIMEOUT;
  794. switch(status)
  795. {
  796. case WAIT_FAILED:
  797. if (bComInit) CoUninitialize();
  798. return (DWORD)-1;
  799. case WAIT_TIMEOUT:
  800. if (NULL != pMngr)
  801. {
  802. EnterCriticalSection(&pMngr->csLock);
  803. start = GetCurrentThreadId();
  804. hTemp = NULL;
  805. for (int i = pMngr->nCount - 1; i >= 0; i--)
  806. {
  807. if (pMngr->pDrives[i].dwThreadId == start)
  808. {
  809. pMngr->pDrives[i].dwThreadId = 0;
  810. hTemp = pMngr->pDrives[i].hThread;
  811. pMngr->pDrives[i].hThread = NULL;
  812. }
  813. }
  814. LeaveCriticalSection(&pMngr->csLock);
  815. //while (WAIT_IO_COMPLETION == WaitForMultipleObjectsEx(0, NULL, TRUE, 0, TRUE));
  816. while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION);
  817. }
  818. result = 2;
  819. run = FALSE;
  820. break;
  821. case WAIT_IO_COMPLETION: start = GetTickCount(); break;
  822. case WAIT_OBJECT_0:
  823. while (run && PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
  824. {
  825. switch(msg.message)
  826. {
  827. case WM_QUIT:
  828. result = (DWORD)msg.wParam;
  829. run = FALSE;
  830. break;
  831. case WM_EX_QUIT:
  832. PostQuitMessage((INT)msg.wParam);
  833. break;
  834. default:
  835. TranslateMessage(&msg);
  836. DispatchMessageW(&msg);
  837. break;
  838. }
  839. }
  840. break;
  841. }
  842. }
  843. if (bComInit) CoUninitialize();
  844. if (2 == result && hTemp) CloseHandle(hTemp);
  845. hTemp = NULL;
  846. return result;
  847. }
  848. static DWORD CALLBACK PollingThread(LPVOID param)
  849. {
  850. MSG msg;
  851. DWORD status, timeout;
  852. BOOL bComInit;
  853. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
  854. bComInit = ( S_OK == CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
  855. timeout = POLLMEDIUMCHANGE_INTERVAL;
  856. for(;;)
  857. {
  858. DWORD elapsed, start = GetTickCount();
  859. while ((elapsed = GetTickCount() - start) < timeout)
  860. {
  861. status = MsgWaitForMultipleObjectsEx(0, NULL, timeout - elapsed,
  862. QS_ALLINPUT, MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
  863. switch(status)
  864. {
  865. case WAIT_FAILED:
  866. if (bComInit) CoUninitialize();
  867. return (DWORD)-1;
  868. case WAIT_TIMEOUT: PollMediumInfo(0); break;
  869. case WAIT_OBJECT_0:
  870. while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
  871. {
  872. switch(msg.message)
  873. {
  874. case WM_QUIT:
  875. if (bComInit) CoUninitialize();
  876. return (DWORD)msg.wParam;
  877. case WM_EX_QUIT:
  878. PostQuitMessage((INT)msg.wParam);
  879. break;
  880. default:
  881. TranslateMessage(&msg);
  882. DispatchMessageW(&msg);
  883. break;
  884. }
  885. }
  886. break;
  887. }
  888. }
  889. }
  890. }
  891. static void CALLBACK PollMediumInfo(ULONG_PTR param)
  892. {
  893. char letters[32] = {0};
  894. LPCWSTR pszDevName[32] = {0};
  895. INT index, count;
  896. if (!pMngr) return;
  897. count = 0;
  898. EnterCriticalSection(&pMngr->csLock);
  899. for (index =0; index < pMngr->nCount; index++)
  900. {
  901. if (DM_MODE_BURNING != pMngr->pDrives[index].cMode && DM_MODE_RIPPING != pMngr->pDrives[index].cMode)
  902. {
  903. letters[count] = pMngr->pDrives[index].cLetter;
  904. pszDevName[count] = pMngr->pDrives[index].pszDevName;
  905. count++;
  906. }
  907. }
  908. LeaveCriticalSection(&pMngr->csLock);
  909. while(count--)
  910. {
  911. HANDLE hDevice = CreateFileW(pszDevName[count], GENERIC_READ | GENERIC_WRITE,
  912. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  913. if (INVALID_HANDLE_VALUE != hDevice)
  914. {
  915. BYTE sc, asc, ascq;
  916. BOOL bReady, bReportChanges, bNeedRecheck;
  917. DWORD ticks;
  918. bReportChanges = FALSE;
  919. bNeedRecheck = FALSE;
  920. if(!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 2))
  921. {
  922. bReady = FALSE;
  923. }
  924. else bReady = (0x00 == sc || (0x02 == sc && 0x3A == asc));
  925. CloseHandle(hDevice);
  926. EnterCriticalSection(&pMngr->csLock);
  927. for (index =0; index < pMngr->nCount; index++)
  928. {
  929. if (pMngr->pDrives[index].cLetter == letters[count])
  930. {
  931. ticks = GetTickCount();
  932. if (pMngr->pDrives[index].bMediumInserted &&
  933. (ticks - pMngr->pDrives[index].mediumInfo.msLastPolled) > POLLMEDIUMVALIDATE_INTERVAL) bNeedRecheck = TRUE;
  934. pMngr->pDrives[index].mediumInfo.msLastPolled = ticks;
  935. if (bReady && ((0x00 == sc) != pMngr->pDrives[index].bMediumInserted)) bReportChanges = TRUE;
  936. break;
  937. }
  938. }
  939. LeaveCriticalSection(&pMngr->csLock);
  940. if (bReportChanges)
  941. {
  942. if (0 == sc) Medium_Add(letters[count], (DWORD)-1);
  943. else Medium_Remove(letters[count]);
  944. }
  945. else if (bNeedRecheck)
  946. {
  947. QueueInfoAPC(letters[count], APC_IsMediumChanged, (DWORD_PTR)letters[count]);
  948. }
  949. }
  950. }
  951. }
  952. static LRESULT WINAPI ListenerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  953. {
  954. switch(uMsg)
  955. {
  956. case WM_DEVICECHANGE:
  957. Listener_OnDeviceChange(hwnd, (UINT)wParam, (DWORD_PTR)lParam);
  958. break;
  959. }
  960. return DefWindowProcW(hwnd, uMsg, wParam, lParam);
  961. }
  962. static void CALLBACK APC_CheckDrives(ULONG_PTR param)
  963. {
  964. INT index, result, count;
  965. DWORD unitmask, dwOutput;
  966. STORAGE_DEVICE_NUMBER sdn;
  967. DEVICEINFO *pDevInfo;
  968. BYTE buffer[4096] = {0};
  969. if (!pMngr) return;
  970. unitmask = (DWORD)param;
  971. count = 0;
  972. for (int i = 0; i < 26; i++) {if (0x1 & (unitmask >> i)) count++;}
  973. if (!count) return;
  974. pDevInfo = (DEVICEINFO*)calloc(count, sizeof(DEVICEINFO));
  975. if (!pDevInfo) return;
  976. index = 0;
  977. for (int i = 0; i < 26; i++)
  978. {
  979. if (0x1 & unitmask)
  980. {
  981. pDevInfo[index].cLetter = (CHAR)(('A' + i));
  982. index++;
  983. if (index == count) break;
  984. }
  985. unitmask = unitmask >> 1;
  986. }
  987. GetDeviceNames(pDevInfo, count);
  988. for (int i = 0; i < count; i++)
  989. {
  990. HANDLE hDevice = CreateFileW(pDevInfo[i].pszDevName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  991. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  992. if (INVALID_HANDLE_VALUE != hDevice)
  993. {
  994. ZeroMemory(&sdn, sizeof(STORAGE_DEVICE_NUMBER));
  995. result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(STORAGE_DEVICE_NUMBER), &dwOutput, NULL);
  996. pDevInfo->deviceNumber = (result) ? sdn.DeviceNumber : -1;
  997. ZeroMemory(&buffer, sizeof(buffer)/sizeof(BYTE));
  998. result = DeviceIoControl(hDevice, IOCTL_STORAGE_GET_MEDIA_TYPES_EX, NULL, 0, buffer, sizeof(buffer)/sizeof(BYTE), &dwOutput, NULL);
  999. if (result && buffer && (FILE_DEVICE_DVD & ((GET_MEDIA_TYPES*)buffer)->DeviceType)) pDevInfo[i].dwType = DRIVE_TYPE_DVD;
  1000. else pDevInfo[i].dwType = DRIVE_TYPE_CD;
  1001. CloseHandle(hDevice);
  1002. }
  1003. }
  1004. GetDeviceCaps(pDevInfo, count);
  1005. EnterCriticalSection(&pMngr->csLock);
  1006. for (int i = 0; i < count; i++)
  1007. {
  1008. pDevInfo[i].opCode = 0;
  1009. for (index =0; index < pMngr->nCount; index++)
  1010. {
  1011. if (pMngr->pDrives[index].cLetter == pDevInfo[i].cLetter)
  1012. {
  1013. if (-1 == pMngr->pDrives[index].deviceNumber || pMngr->pDrives[index].deviceNumber != pDevInfo[i].deviceNumber)
  1014. pDevInfo[i].opCode = 1;
  1015. break;
  1016. }
  1017. }
  1018. if (pMngr->nCount == index) pDevInfo[i].opCode = 2;
  1019. }
  1020. LeaveCriticalSection(&pMngr->csLock);
  1021. for (int i = 0; i < count; i++)
  1022. {
  1023. if (pDevInfo[i].opCode) Drive_Add(&pDevInfo[i]);
  1024. }
  1025. if (pDevInfo)
  1026. {
  1027. for (int i = 0; i<count; i++)
  1028. {
  1029. if (pDevInfo[i].pszDevName) free(pDevInfo[i].pszDevName);
  1030. }
  1031. free(pDevInfo);
  1032. }
  1033. }
  1034. static void CALLBACK APC_IsMediumChanged(ULONG_PTR param)
  1035. {
  1036. INT opCode;
  1037. DWORD serial;
  1038. wchar_t devname[4] = L"X:\\";
  1039. if (!pMngr) return;
  1040. opCode = 0;
  1041. devname[0] = (char)(0xFF & param);
  1042. if (devname[0])
  1043. {
  1044. BOOL result;
  1045. serial = 0;
  1046. result = GetVolumeInformationW(devname, NULL, 0, &serial, NULL, NULL, NULL, 0);
  1047. if (!result) serial = 0; // perhaps this is empty recordable disc
  1048. EnterCriticalSection(&pMngr->csLock);
  1049. for (INT index =0; index < pMngr->nCount; index++)
  1050. {
  1051. if (pMngr->pDrives[index].cLetter == (char)param )
  1052. {
  1053. pMngr->pDrives[index].mediumInfo.msLastPolled = GetTickCount();
  1054. if (!pMngr->pDrives[index].bMediumInserted && result) opCode = 0x02;
  1055. else if (pMngr->pDrives[index].mediumInfo.serialNumber != serial)
  1056. {
  1057. if (-1 == pMngr->pDrives[index].mediumInfo.serialNumber) pMngr->pDrives[index].mediumInfo.serialNumber = serial;
  1058. else opCode = 0x03;
  1059. }
  1060. break;
  1061. }
  1062. }
  1063. LeaveCriticalSection(&pMngr->csLock);
  1064. if (0x01 & opCode) Medium_Remove((char)param);
  1065. if (0x02 & opCode) Medium_Add((char)param, serial);
  1066. }
  1067. }
  1068. static void CALLBACK APC_AsyncOp_Complete(ULONG_PTR param)
  1069. {
  1070. DM_NOTIFY_PARAM *phdr = (DM_NOTIFY_PARAM*)param;
  1071. if (phdr->hReserved)
  1072. {
  1073. CloseHandle(phdr->hReserved);
  1074. phdr->hReserved = NULL;
  1075. }
  1076. if (phdr->callback)
  1077. {
  1078. if (phdr->uMsg)
  1079. {
  1080. if (IsWindow((HWND)phdr->callback)) SendMessageW((HWND)phdr->callback, phdr->uMsg, (WPARAM)DMW_OPCOMPLETED, (LPARAM)phdr);
  1081. }
  1082. else ((DMNPROC)phdr->callback)(DMW_OPCOMPLETED, (INT_PTR)param);
  1083. }
  1084. if (phdr->fnFree)
  1085. {
  1086. phdr->fnFree(phdr);
  1087. }
  1088. }
  1089. static void AsycOp_Complete(DM_NOTIFY_PARAM *param)
  1090. {
  1091. if (param) QueueUserAPC(APC_AsyncOp_Complete, param->hReserved, (ULONG_PTR)param);
  1092. }
  1093. static void CALLBACK APC_GetUnitInfo(ULONG_PTR param)
  1094. {
  1095. DWORD unit;
  1096. DM_UNITINFO_PARAM *puip;
  1097. puip = (DM_UNITINFO_PARAM*)param;
  1098. puip->header.opCode = DMOP_UNITINFO;
  1099. unit = CheckLetter(puip->header.cLetter);
  1100. if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE;
  1101. else
  1102. {
  1103. DWORD ready = 0;
  1104. CHAR buffer[512] = {0};
  1105. puip->header.result = PrimoSDKHelper_UnitInfo(&unit, &puip->dwType,
  1106. ((DMF_DESCRIPTION & puip->header.fFlags) || (DMF_FIRMWARE & puip->header.fFlags)) ? (BYTE*)buffer: NULL,
  1107. (DMF_READY & puip->header.fFlags) ? &ready : NULL);
  1108. if (PRIMOSDK_OK == puip->header.result)
  1109. {
  1110. if (DMF_READY & puip->header.fFlags) puip->bReady = (0 != ready);
  1111. if (DMF_DESCRIPTION & puip->header.fFlags)
  1112. {
  1113. INT len = lstrlenA(buffer);
  1114. if (len > 5) len -= 5;
  1115. if (!puip->pszDesc || puip->cchDesc < (len + 1)) puip->cchDesc = -(len + 1);
  1116. else
  1117. {
  1118. StringCchCopyNA(puip->pszDesc, puip->cchDesc, buffer, len);
  1119. puip->cchDesc = len;
  1120. }
  1121. }
  1122. if (DMF_FIRMWARE & puip->header.fFlags)
  1123. {
  1124. LPSTR p;
  1125. INT len = lstrlenA(buffer);
  1126. p = buffer + (len - ((len > 5) ? 4 : 0));
  1127. if (!puip->pszFirmware || puip->cchFirmware < 4) puip->cchFirmware = -4;
  1128. else
  1129. {
  1130. StringCchCopyA(puip->pszFirmware, puip->cchFirmware, p);
  1131. puip->cchFirmware = 4;
  1132. }
  1133. }
  1134. }
  1135. }
  1136. AsycOp_Complete(&puip->header);
  1137. }
  1138. static void CALLBACK APC_GetUnitInfo2(ULONG_PTR param)
  1139. {
  1140. DWORD unit;
  1141. DM_UNITINFO2_PARAM *puip;
  1142. puip = (DM_UNITINFO2_PARAM*)param;
  1143. puip->header.opCode = DMOP_UNITINFO2;
  1144. unit = CheckLetter(puip->header.cLetter);
  1145. if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) puip->header.result = PRIMOSDK_CMDSEQUENCE;
  1146. else
  1147. {
  1148. BOOL bReady;
  1149. DWORD szTypes[32], rfu;
  1150. if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
  1151. {
  1152. SleepEx(1000, TRUE);
  1153. QueueUserAPC(APC_GetUnitInfo2, GetCurrentThread(), param);
  1154. return;
  1155. }
  1156. puip->header.result = PrimoSDKHelper_UnitInfo2(&unit, szTypes, &puip->dwClassId, &puip->dwBusType, &rfu);
  1157. if (PRIMOSDK_OK == puip->header.result)
  1158. {
  1159. if (DMF_TYPES & puip->header.fFlags)
  1160. {
  1161. INT len;
  1162. for (len = 0; szTypes[len] != 0xFFFFFFFF; len++);
  1163. if (!puip->pdwTypes || puip->nTypes < len) puip->nTypes = -len;
  1164. else
  1165. {
  1166. puip->nTypes = len;
  1167. if (len) CopyMemory(puip->pdwTypes, szTypes, sizeof(DWORD)*len);
  1168. }
  1169. }
  1170. }
  1171. }
  1172. AsycOp_Complete(&puip->header);
  1173. }
  1174. static void CALLBACK APC_GetDiscInfoEx(ULONG_PTR param)
  1175. {
  1176. DWORD unit;
  1177. DM_DISCINFOEX_PARAM *pdip;
  1178. pdip = (DM_DISCINFOEX_PARAM*)param;
  1179. pdip->header.opCode = DMOP_DISCINFO;
  1180. unit = CheckLetter(pdip->header.cLetter);
  1181. if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE;
  1182. else
  1183. {
  1184. BOOL bReady;
  1185. DWORD dwFlags, dwErasable;
  1186. if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
  1187. {
  1188. SleepEx(1000, TRUE);
  1189. QueueUserAPC(APC_GetDiscInfoEx, GetCurrentThread(), param);
  1190. return;
  1191. }
  1192. dwFlags = (DMF_DRIVEMODE_TAO & pdip->header.fFlags);
  1193. pdip->header.result = PrimoSDKHelper_DiscInfoEx(&unit, dwFlags,
  1194. (DMF_MEDIUMTYPE & pdip->header.fFlags) ? &pdip->dwMediumType : NULL,
  1195. (DMF_MEDIUMFORMAT & pdip->header.fFlags) ? &pdip->dwMediumFormat : NULL,
  1196. &dwErasable,
  1197. (DMF_TRACKS & pdip->header.fFlags) ? &pdip->dwTracks: NULL,
  1198. (DMF_USED & pdip->header.fFlags) ? &pdip->dwUsed : NULL,
  1199. (DMF_FREE & pdip->header.fFlags) ? &pdip->dwFree : NULL);
  1200. if (PRIMOSDK_OK == pdip->header.result) pdip->bErasable = (0 != dwErasable);
  1201. }
  1202. AsycOp_Complete(&pdip->header);
  1203. }
  1204. static void CALLBACK APC_GetDiscInfo2(ULONG_PTR param)
  1205. {
  1206. DWORD unit;
  1207. DM_DISCINFO2_PARAM *pdip;
  1208. pdip = (DM_DISCINFO2_PARAM*)param;
  1209. pdip->header.opCode = DMOP_DISCINFO2;
  1210. unit = CheckLetter(pdip->header.cLetter);
  1211. if (!unit || (!PrimoSDKHelper_IsInitialized() && !PrimoSDKHelper_Initialize())) pdip->header.result = PRIMOSDK_CMDSEQUENCE;
  1212. else
  1213. {
  1214. DWORD rfu, medium, protectedDVD, flags;
  1215. BOOL bReady;
  1216. if (DriveManager_IsUnitReady((char)unit, &bReady) && !bReady)
  1217. {
  1218. SleepEx(1000, TRUE);
  1219. QueueUserAPC(APC_GetDiscInfo2, GetCurrentThread(), param);
  1220. return;
  1221. }
  1222. pdip->header.result = PrimoSDKHelper_DiscInfo2(&unit,
  1223. (DMF_MEDIUM & pdip->header.fFlags) ? &pdip->dwMedium : (DMF_MEDIUMEX & pdip->header.fFlags) ? &medium : NULL,
  1224. (DMF_PROTECTEDDVD & pdip->header.fFlags) ? &protectedDVD : NULL,
  1225. (DMF_PACKETWRITTEN & pdip->header.fFlags) ? &flags : NULL,
  1226. (DMF_MEDIUMEX & pdip->header.fFlags) ? &pdip->dwMediumEx : NULL,
  1227. &rfu);
  1228. if (PRIMOSDK_OK == pdip->header.result)
  1229. {
  1230. if (DMF_PROTECTEDDVD & pdip->header.fFlags) pdip->bProtectedDVD = (0 != protectedDVD);
  1231. if (DMF_PACKETWRITTEN & pdip->header.fFlags) pdip->bPacketWritten = (0 != (PRIMOSDK_PACKETWRITTEN & protectedDVD));
  1232. }
  1233. }
  1234. AsycOp_Complete(&pdip->header);
  1235. }
  1236. static void CALLBACK APC_GetTitle(ULONG_PTR param)
  1237. {
  1238. CHAR cLetter;
  1239. DM_TITLE_PARAM *pdtp;
  1240. pdtp = (DM_TITLE_PARAM*)param;
  1241. pdtp->header.opCode = DMOP_TITLE;
  1242. cLetter = CheckLetter(pdtp->header.cLetter);
  1243. pdtp->header.result = PRIMOSDK_CMDSEQUENCE;
  1244. if (cLetter && pdtp->pszTitle)
  1245. {
  1246. wchar_t name[] = L"X:\\";
  1247. MCIDEVICEID devId;
  1248. MCI_OPEN_PARMS op = {0};
  1249. MCI_GENERIC_PARMS gp = {0};
  1250. MCI_STATUS_PARMS sp = {0};
  1251. name[0] = cLetter;
  1252. op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO;
  1253. op.lpstrElementName = name;
  1254. if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op))
  1255. {
  1256. HRESULT hr;
  1257. devId = op.wDeviceID;
  1258. sp.dwItem = MCI_STATUS_MEDIA_PRESENT;
  1259. INT present = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
  1260. if (present)
  1261. {
  1262. INT nTracks;
  1263. BOOL bAudio;
  1264. wchar_t szVolume[256] = {0};
  1265. // check if we have at least one audio track
  1266. sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  1267. nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1;
  1268. bAudio = FALSE;
  1269. if (nTracks > 0)
  1270. {
  1271. sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  1272. for (sp.dwTrack = 1; sp.dwTrack <= (UINT)nTracks && !bAudio; sp.dwTrack++)
  1273. {
  1274. mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
  1275. bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn);
  1276. }
  1277. if (bAudio) WASABI_API_LNGSTRINGW_BUF(IDS_CD_AUDIO, szVolume, sizeof(szVolume)/sizeof(wchar_t));
  1278. else
  1279. {
  1280. INT result;
  1281. wchar_t devname[4] = L"X:\\";
  1282. devname[0] = cLetter;
  1283. result = GetVolumeInformationW(devname, szVolume, sizeof(szVolume)/sizeof(wchar_t), NULL, NULL, NULL, NULL, 0);
  1284. if (!result) WASABI_API_LNGSTRINGW_BUF(IDS_DISC_DATA, szVolume, sizeof(szVolume)/sizeof(wchar_t));
  1285. }
  1286. }
  1287. else WASABI_API_LNGSTRINGW_BUF(IDS_DISC_BLANK, szVolume, sizeof(szVolume)/sizeof(wchar_t));
  1288. hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s (%c:)", szVolume, cLetter);
  1289. }
  1290. else
  1291. {
  1292. INT nDriveType, nDriveCap;
  1293. DWORD type;
  1294. wchar_t szDriveType[32] = {0}, szDriveCap[64] = {0};
  1295. type = DriveManager_GetDriveType(cLetter);
  1296. if ((DRIVE_TYPE_UNKNOWN | DRIVE_CAP_UNKNOWN) == type) type = DRIVE_TYPE_CD;
  1297. nDriveCap = ((DRIVE_CAP_R | DRIVE_CAP_RW) & type) ? IDS_RECORDER_CAP : IDS_DRIVE_CAP;
  1298. nDriveType = (IDS_DRIVE_CAP == nDriveCap && (DRIVE_TYPE_DVD & type)) ? IDS_DVD : IDS_CD;
  1299. WASABI_API_LNGSTRINGW_BUF(nDriveType, szDriveType, sizeof(szDriveType)/sizeof(wchar_t));
  1300. WASABI_API_LNGSTRINGW_BUF(nDriveCap, szDriveCap, sizeof(szDriveCap)/sizeof(wchar_t));
  1301. hr = StringCchPrintfW(pdtp->pszTitle, pdtp->cchTitle, L"%s %s (%C:)", szDriveType, szDriveCap, cLetter);
  1302. }
  1303. pdtp->header.result = hr;
  1304. mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp);
  1305. }
  1306. }
  1307. AsycOp_Complete(&pdtp->header);
  1308. }
  1309. static void CALLBACK APC_DriveScan(ULONG_PTR param)
  1310. {
  1311. char i;
  1312. char root[] = "A:\\";
  1313. DWORD unitmask;
  1314. DEVICEINFO di = {0};
  1315. /// detect drives
  1316. unitmask = GetLogicalDrives();
  1317. di.deviceNumber = -1;
  1318. di.dwType = DRIVE_TYPE_CD;
  1319. for (i = 0; i < 26; ++i)
  1320. {
  1321. if (0x1 & (unitmask >> i))
  1322. {
  1323. root[0] = ('A' + i);
  1324. if(DRIVE_CDROM != GetDriveTypeA(root)) unitmask &= ~(1 << i);
  1325. else
  1326. {
  1327. di.cLetter = root[0];
  1328. Drive_Add(&di);
  1329. }
  1330. }
  1331. }
  1332. APC_CheckDrives((ULONG_PTR)unitmask);
  1333. }
  1334. #define MAX_TEST_ATTEMPT 20
  1335. static void CALLBACK APC_Eject(ULONG_PTR param)
  1336. {
  1337. INT nCmd;
  1338. CHAR cLetter;
  1339. BYTE sc(0), asc(0), ascq(0);
  1340. nCmd = HIWORD(param);
  1341. cLetter = CheckLetter((CHAR)param);
  1342. if (cLetter && DM_MODE_READY == DriveManager_GetDriveMode(cLetter))
  1343. {
  1344. BOOL bSuccess;
  1345. HANDLE hDevice;
  1346. hDevice = CreateFileW(GetDeviceName(cLetter), GENERIC_READ | GENERIC_WRITE,
  1347. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  1348. if (INVALID_HANDLE_VALUE != hDevice)
  1349. {
  1350. DWORD dwOutput;
  1351. LARGE_INTEGER start, finish;
  1352. bSuccess = SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3);
  1353. if (!bSuccess && ERROR_SEM_TIMEOUT == GetLastError())
  1354. {
  1355. bSuccess = TRUE;
  1356. sc = 0xFF;
  1357. }
  1358. if (bSuccess && (0 == sc || (0x02 == sc && 0x3A == asc)))
  1359. {
  1360. INT opCode;
  1361. opCode = (DM_EJECT_REMOVE == nCmd || 0x00 == sc || (0x3A == asc && 0x01 == ascq)) ?
  1362. IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA;
  1363. QueryPerformanceCounter(&start);
  1364. bSuccess = DeviceIoControl(hDevice, opCode, NULL, 0, NULL, 0, &dwOutput, NULL);
  1365. QueryPerformanceCounter(&finish);
  1366. if (bSuccess && DM_EJECT_CHANGE == nCmd && 0x00 != sc && 0x00 == ascq)
  1367. {
  1368. finish.QuadPart -= start.QuadPart;
  1369. if (finish.QuadPart < freq.QuadPart && (finish.QuadPart*100000 / freq.QuadPart) < 200)
  1370. {
  1371. // test unit redy
  1372. INT i;
  1373. sc = 0x02; asc = 0x04; ascq = 0x01;
  1374. for (i = 0; i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x04 == asc && 0x01 == ascq; i++)
  1375. {
  1376. Sleep(50);
  1377. if (!SPTI_TestUnitReady(hDevice, &sc, &asc, &ascq, 3) && ERROR_SEM_TIMEOUT == GetLastError())
  1378. i = MAX_TEST_ATTEMPT;
  1379. }
  1380. if (i < MAX_TEST_ATTEMPT && 0x02 == sc && 0x3A ==asc)
  1381. {
  1382. DeviceIoControl(hDevice, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwOutput, NULL);
  1383. }
  1384. sc = 0x00;
  1385. }
  1386. }
  1387. }
  1388. CloseHandle(hDevice);
  1389. }
  1390. else bSuccess = FALSE;
  1391. if (!bSuccess)
  1392. { // we can try MCI
  1393. }
  1394. else if (0x00 != sc && !(0x02 == sc && 0x3A == asc))
  1395. {
  1396. SleepEx(200, TRUE);
  1397. QueueUserAPC(APC_Eject, GetCurrentThread(), param);
  1398. return;
  1399. }
  1400. }
  1401. }
  1402. static void CALLBACK APC_GetMCIInfo(ULONG_PTR param)
  1403. {
  1404. CHAR cLetter;
  1405. MCI_OPEN_PARMS op = {0};
  1406. DM_MCI_PARAM *pmcip;
  1407. pmcip = (DM_MCI_PARAM*)param;
  1408. pmcip->header.opCode = DMOP_MCIINFO;
  1409. cLetter = CheckLetter(pmcip->header.cLetter);
  1410. pmcip->header.result = PRIMOSDK_CMDSEQUENCE;
  1411. if (cLetter)
  1412. {
  1413. wchar_t name[] = L"X:\\";
  1414. MCIDEVICEID devId;
  1415. MCI_INFO_PARMS ip = {0};
  1416. MCI_GENERIC_PARMS gp = {0};
  1417. MCI_STATUS_PARMS sp = {0};
  1418. name[0] = cLetter;
  1419. op.lpstrDeviceType = (LPWSTR)MCI_DEVTYPE_CD_AUDIO;
  1420. op.lpstrElementName = name;
  1421. if (!mciSendCommandW(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD_PTR)&op))
  1422. {
  1423. WCHAR buffer[512] = {0};
  1424. INT nMaxTracks = pmcip->nTracks;
  1425. devId = op.wDeviceID;
  1426. if ((DMF_TRACKCOUNT | DMF_TRACKSINFO) & pmcip->header.fFlags)
  1427. {
  1428. sp.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  1429. pmcip->nTracks = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (INT)sp.dwReturn : -1;
  1430. }
  1431. if (DMF_READY & pmcip->header.fFlags)
  1432. {
  1433. sp.dwItem = MCI_STATUS_READY;
  1434. pmcip->bReady = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
  1435. }
  1436. if (DMF_MODE & pmcip->header.fFlags)
  1437. {
  1438. sp.dwItem = MCI_STATUS_MODE;
  1439. pmcip->uMode = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (UINT)sp.dwReturn : 0;
  1440. }
  1441. if (DMF_MEDIUMPRESENT & pmcip->header.fFlags)
  1442. {
  1443. sp.dwItem = MCI_STATUS_MEDIA_PRESENT;
  1444. pmcip->bMediumPresent = (!mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD_PTR)&sp)) ? (BOOL)sp.dwReturn : 0;
  1445. }
  1446. if (DMF_MEDIUMUID & pmcip->header.fFlags)
  1447. {
  1448. ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t);
  1449. ip.lpstrReturn= buffer;
  1450. if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_IDENTITY, (DWORD_PTR)&ip))
  1451. {
  1452. INT len;
  1453. len = lstrlenW(ip.lpstrReturn);
  1454. if (S_OK == StringCchCopyW(pmcip->pszMediumUID, pmcip->cchMediumUID, ip.lpstrReturn))
  1455. {
  1456. pmcip->cchMediumUID = len;
  1457. }
  1458. else pmcip->cchMediumUID = 0 - (len + 1);
  1459. }
  1460. else pmcip->cchMediumUID = -1;
  1461. }
  1462. if (DMF_MEDIUMUPC & pmcip->header.fFlags)
  1463. {
  1464. ip.dwCallback = NULL;
  1465. ip.dwRetSize = sizeof(buffer)/sizeof(wchar_t);
  1466. ip.lpstrReturn = buffer;
  1467. if (!mciSendCommandW(devId, MCI_INFO, MCI_WAIT | MCI_INFO_MEDIA_UPC, (DWORD_PTR)&ip))
  1468. {
  1469. INT len;
  1470. len = lstrlenW(ip.lpstrReturn);
  1471. if (S_OK == StringCchCopyW(pmcip->pszMediumUPC, pmcip->cchMediumUPC, ip.lpstrReturn))
  1472. {
  1473. pmcip->cchMediumUPC = len;
  1474. }
  1475. else pmcip->cchMediumUPC = 0 - (len + 1);
  1476. }
  1477. else pmcip->cchMediumUPC = -1;
  1478. }
  1479. if (DMF_TRACKSINFO & pmcip->header.fFlags)
  1480. {
  1481. MCI_SET_PARMS setp;
  1482. if (nMaxTracks < pmcip->nTracks) pmcip->nTracks = (0 - pmcip->nTracks);
  1483. else
  1484. {
  1485. INT prevPos(0), length(0);
  1486. setp.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  1487. mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp);
  1488. for (int i = pmcip->nTracks; i > 0; i--)
  1489. {
  1490. sp.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  1491. sp.dwTrack = i;
  1492. mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
  1493. BOOL bAudio = (MCI_CDA_TRACK_AUDIO == sp.dwReturn);
  1494. sp.dwItem = MCI_STATUS_POSITION;
  1495. sp.dwTrack = i;
  1496. mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
  1497. if (i != pmcip->nTracks) length = prevPos - (INT)sp.dwReturn;
  1498. prevPos = (INT)sp.dwReturn;
  1499. if (i == pmcip->nTracks)
  1500. {
  1501. sp.dwItem = MCI_STATUS_LENGTH;
  1502. sp.dwTrack = i;
  1503. mciSendCommandW(devId, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD_PTR)&sp);
  1504. length = (INT)sp.dwReturn;
  1505. }
  1506. pmcip->pTracks[i- 1] = (0x7FFFFFF & length) | ((bAudio) ? 0x80000000 : 0);
  1507. }
  1508. setp.dwTimeFormat = MCI_FORMAT_TMSF;
  1509. mciSendCommandW(devId, MCI_SET, MCI_WAIT | MCI_SET_TIME_FORMAT, (DWORD_PTR)&setp);
  1510. }
  1511. }
  1512. mciSendCommandW(devId, MCI_CLOSE, MCI_WAIT, (DWORD_PTR)&gp);
  1513. pmcip->header.result = PRIMOSDK_OK;
  1514. }
  1515. }
  1516. AsycOp_Complete(&pmcip->header);
  1517. }
  1518. static void CALLBACK APC_GetIMAPIInfo(ULONG_PTR param)
  1519. {
  1520. CHAR cLetter;
  1521. BOOL bReady;
  1522. HRESULT hr(S_FALSE);
  1523. IDiscMaster *pdm;
  1524. IDiscRecorder *pdr;
  1525. IEnumDiscRecorders *per;
  1526. ULONG nActual;
  1527. wchar_t szDevName[] = L"X:\\";
  1528. wchar_t szTargetName[128] = {0};
  1529. DM_IMAPI_PARAM *pIMAPI;
  1530. pIMAPI = (DM_IMAPI_PARAM*)param;
  1531. cLetter = CheckLetter(pIMAPI->header.cLetter);
  1532. if (DriveManager_IsUnitReady(cLetter, &bReady) && !bReady)
  1533. {
  1534. SleepEx(1000, TRUE);
  1535. QueueUserAPC(APC_GetIMAPIInfo, GetCurrentThread(), param);
  1536. return;
  1537. }
  1538. pIMAPI->header.opCode = DMOP_IMAPIINFO;
  1539. pIMAPI->bRecorder = FALSE;
  1540. pIMAPI->header.result = (DWORD)E_INVALIDARG;
  1541. szDevName[0] = cLetter;
  1542. if (cLetter && QueryDosDeviceW(szDevName, szTargetName, sizeof(szTargetName)/sizeof(wchar_t)))
  1543. {
  1544. hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IDiscMaster, (void**)&pdm);
  1545. if (SUCCEEDED(hr))
  1546. {
  1547. hr = pdm->Open();
  1548. if (SUCCEEDED(hr))
  1549. {
  1550. IEnumDiscMasterFormats *pef;
  1551. hr = pdm->EnumDiscMasterFormats(&pef);
  1552. if (SUCCEEDED(hr))
  1553. {
  1554. IID pFormats[2];
  1555. hr = pef->Next(sizeof(pFormats)/sizeof(IID), pFormats, &nActual);
  1556. if (SUCCEEDED(hr))
  1557. {
  1558. while(nActual--) { if (IID_IRedbookDiscMaster == pFormats[nActual]) break; }
  1559. if (nActual != ((ULONG)-1))
  1560. {
  1561. IRedbookDiscMaster *pdf;
  1562. hr = pdm->SetActiveDiscMasterFormat(IID_IRedbookDiscMaster, (void**)&pdf);
  1563. if (SUCCEEDED(hr))
  1564. {
  1565. pdf->Release();
  1566. hr = pdm->EnumDiscRecorders(&per);
  1567. if (SUCCEEDED(hr))
  1568. {
  1569. while (S_OK== per->Next(1, &pdr, &nActual) && nActual > 0)
  1570. {
  1571. BSTR bstrPath;
  1572. hr = pdr->GetPath(&bstrPath);
  1573. if (SUCCEEDED(hr))
  1574. {
  1575. if (0 == lstrcmp(szTargetName, bstrPath))
  1576. {
  1577. pIMAPI->bRecorder = TRUE;
  1578. if ((DMF_BASEPNPID & pIMAPI->header.fFlags) && FAILED(pdr->GetBasePnPID(&pIMAPI->bstrBasePnPID))) pIMAPI->bstrBasePnPID = NULL;
  1579. if ((DMF_DISPLAYNAMES & pIMAPI->header.fFlags) && FAILED(pdr->GetDisplayNames(&pIMAPI->bstrVendorID, &pIMAPI->bstrProductID, &pIMAPI->bstrRevision)))
  1580. {
  1581. pIMAPI->bstrVendorID = NULL;
  1582. pIMAPI->bstrProductID = NULL;
  1583. pIMAPI->bstrRevision = NULL;
  1584. }
  1585. if (DMF_PATH & pIMAPI->header.fFlags)
  1586. {
  1587. pIMAPI->bstrPath = bstrPath;
  1588. bstrPath = NULL;
  1589. }
  1590. if ((DMF_DRIVESTATE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderState(&pIMAPI->ulDriveState))) pIMAPI->ulDriveState = (ULONG)-1;
  1591. if ((DMF_DRIVETYPE & pIMAPI->header.fFlags) && FAILED(pdr->GetRecorderType(&pIMAPI->fDriveType))) pIMAPI->fDriveType = 0;
  1592. if ((DMF_QUERYMEDIATYPE | DMF_QUERYMEDIAINFO) & pIMAPI->header.fFlags)
  1593. {
  1594. BOOL bTypeOk(FALSE), bInfoOk(FALSE);
  1595. if (SUCCEEDED(pdr->OpenExclusive()))
  1596. {
  1597. if (0 == (DMF_QUERYMEDIATYPE & pIMAPI->header.fFlags) ||
  1598. SUCCEEDED(pdr->QueryMediaType(&pIMAPI->fMediaType, &pIMAPI->fMediaFlags))) bTypeOk = TRUE;
  1599. if (0 == (DMF_QUERYMEDIAINFO & pIMAPI->header.fFlags) ||
  1600. SUCCEEDED(pdr->QueryMediaInfo(&pIMAPI->bSessions, &pIMAPI->bLastTrack, &pIMAPI->ulStartAddress,
  1601. &pIMAPI->ulNextWritable, &pIMAPI->ulFreeBlocks))) bInfoOk = TRUE;
  1602. pdr->Close();
  1603. }
  1604. if (!bTypeOk)
  1605. {
  1606. pIMAPI->fMediaType = -1;
  1607. pIMAPI->fMediaFlags = -1;
  1608. }
  1609. if (!bInfoOk)
  1610. {
  1611. pIMAPI->bLastTrack = 0;
  1612. pIMAPI->bSessions = 0;
  1613. pIMAPI->ulFreeBlocks = 0;
  1614. pIMAPI->ulNextWritable = 0;
  1615. pIMAPI->ulStartAddress = 0;
  1616. }
  1617. }
  1618. break;
  1619. }
  1620. if (bstrPath) SysFreeString(bstrPath);
  1621. }
  1622. pdr->Release();
  1623. }
  1624. per->Release();
  1625. }
  1626. }
  1627. }
  1628. }
  1629. pef->Release();
  1630. }
  1631. pdm->Close();
  1632. }
  1633. pdm->Release();
  1634. }
  1635. }
  1636. pIMAPI->header.result = hr;
  1637. AsycOp_Complete(&pIMAPI->header);
  1638. }