Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3181 lines
90 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | MCI.C |
  3. | |
  4. | This file contains the routines which the media player uses to interact with |
  5. | the Media Control Interface (MCI). |
  6. | |
  7. | (C) Copyright Microsoft Corporation 1991. All rights reserved. |
  8. | |
  9. | Revision History |
  10. | Oct-1992 MikeTri Ported to WIN32 / WIN16 common code |
  11. | |
  12. +-----------------------------------------------------------------------------*/
  13. #undef NOGDICAPMASKS // CC_*, LC_*, PC_*, CP_*, TC_*, RC_
  14. #undef NOSCROLL
  15. #undef NOWINOFFSETS
  16. #undef NODRAWTEXT
  17. #include <windows.h>
  18. #include <mmsystem.h>
  19. #include <mmddk.h>
  20. #include <stdlib.h>
  21. #include <shellapi.h>
  22. #include "digitalv.h"
  23. #include "mpole.h"
  24. #include "mplayer.h"
  25. #include "ctrls.h"
  26. #include "errprop.h"
  27. #include "utils.h"
  28. #ifndef MCI_MCIAVI_PLAY_WINDOW
  29. // force MCIAVI to play windowed in play in place
  30. #define MCI_MCIAVI_PLAY_WINDOW 0x01000000L
  31. #endif
  32. // gets the name of the current device
  33. STATICDT SZCODE aszInfoProduct[] = TEXT("info zyzsmag product");
  34. STATICDT SZCODE aszMMPName[] = TEXT("Microsoft Multimedia Movie Player");
  35. //#ifdef CHICAGO_PRODUCT
  36. #define NEW_MCI_DIALOG
  37. //#endif
  38. #ifdef NEW_MCI_DIALOG
  39. STATICDT SZCODE aszMCIAVIOpt[] = TEXT("Software\\Microsoft\\Multimedia\\Video For Windows\\MCIAVI");
  40. STATICDT SZCODE aszDefVideoOpt[] = TEXT("DefaultOptions");
  41. //
  42. // !!! Caution. These are stolen from \MCIAVI\graphic.h and are registry values
  43. // for MCIAVI.
  44. //
  45. #define MCIAVIO_ZOOMBY2 0x00000100L
  46. #define MCIAVIO_1QSCREENSIZE 0x00010000L
  47. #define MCIAVIO_2QSCREENSIZE 0x00020000L
  48. #define MCIAVIO_3QSCREENSIZE 0x00040000L
  49. #define MCIAVIO_MAXWINDOWSIZE 0x00080000L
  50. #define MCIAVIO_DEFWINDOWSIZE 0x00000000L
  51. #define MCIAVIO_WINDOWSIZEMASK 0x000f0000L
  52. #endif /* NEW_MCI_DIALOG */
  53. extern HMENU ghMenu;
  54. /*
  55. * global variables
  56. *
  57. * <gwDeviceID> is the MCI device ID of the currently-open device, or NULL
  58. * if no device is open. <gdwMediaLength> is the length of the entire medium
  59. * in milliseconds. If <gwDeviceID> is not NULL, then:
  60. * -- <gwNumTracks> is the number of tracks on the medium, or 0 if the
  61. * medium doesn't support tracks
  62. * -- <gwFirstTrack> is the number of the first track, currently constrained
  63. * to be 0 or 1.
  64. * -- <gadwTrackStart> is an array; the i-th element specifies the position
  65. * of track i (starting from track 0), in milliseconds from the beginning
  66. * of the medium
  67. * -- <gfCanEject> is TRUE if the medium can be ejected
  68. *
  69. */
  70. UINT gwDeviceID; /* MCI device ID of the current device */
  71. UINT gwDeviceType; /* DTMCI_ flags of current device */
  72. DWORD gdwMediaLength; /* length in msec of the entire medium */
  73. DWORD gdwMediaStart; /* start time in msec of medium */
  74. UINT gwNumTracks; /* # of tracks in the medium */
  75. UINT gwFirstTrack; /* # of first track */
  76. DWORD NEAR * gadwTrackStart; /* array of track start positions */
  77. DWORD gdwLastSeekToPosition; /* Last requested seek position */
  78. int extHeight;
  79. int extWidth;
  80. STATICDT SZCODE aszMPlayerAlias[] = TEXT("zyzsmag");
  81. STATICDT SZCODE aszStatusCommand[] = TEXT("status zyzsmag mode");
  82. STATICDT SZCODE aszStatusWindow[] = TEXT("status zyzsmag window handle");
  83. STATICDT SZCODE aszWindowShow[] = TEXT("window zyzsmag state show");
  84. STATICDT SZCODE aszWindowHide[] = TEXT("window zyzsmag state hide");
  85. STATICDT SZCODE aszSeekExactOn[] = TEXT("set zyzsmag seek exactly on");
  86. STATICDT SZCODE aszSeekExactOff[] = TEXT("set zyzsmag seek exactly off");
  87. STATICDT SZCODE aszSeekExact[] = TEXT("status zyzsmag seek exactly");
  88. STATICDT SZCODE aszMCI[] = MCI_SECTION;
  89. extern UINT gwCurScale; // either ID_FRAMES, ID_TIME, ID_TRACKS
  90. //#define MCI_CONFIG 0x900 // these are not found in MMSYSTEM.H
  91. //#define MCI_TEST 0x00000020L
  92. HWND ghwndMCI = NULL; /* current window for window objects */
  93. #ifdef NEW_MCI_DIALOG
  94. RECT grcInitSize = { 0, 0, 0, 0 };
  95. #endif
  96. RECT grcSize; /* size of MCI object */
  97. BOOL gfInPlayMCI = FALSE;
  98. extern WNDPROC gfnMCIWndProc;
  99. extern HWND ghwndSubclass;
  100. /* Status mapping stuff:
  101. */
  102. typedef struct _MCI_STATUS_MAPPING
  103. {
  104. WORD Mode;
  105. WORD ResourceID;
  106. LPTSTR pString;
  107. }
  108. MCI_STATUS_MAPPING, *PMCI_STATUS_MAPPING;
  109. MCI_STATUS_MAPPING MCIStatusMapping[] =
  110. {
  111. { MCI_MODE_NOT_READY, IDS_SSNOTREADY, NULL },
  112. { MCI_MODE_STOP, IDS_SSSTOPPED, NULL },
  113. { MCI_MODE_PLAY, IDS_SSPLAYING, NULL },
  114. { MCI_MODE_RECORD, IDS_SSRECORDING, NULL },
  115. { MCI_MODE_SEEK, IDS_SSSEEKING, NULL },
  116. { MCI_MODE_PAUSE, IDS_SSPAUSED, NULL },
  117. { MCI_MODE_OPEN, IDS_SSOPEN, NULL },
  118. { MCI_VD_MODE_PARK, IDS_SSPARKED, NULL },
  119. { 0, IDS_SSUNKNOWN, NULL }
  120. };
  121. static TCHAR szNULL[] = TEXT("");
  122. /* Devices we know about, as they appear in system.ini, or the registry:
  123. */
  124. SZCODE szCDAudio[] = TEXT("cdaudio");
  125. SZCODE szVideoDisc[] = TEXT("videodisc");
  126. SZCODE szSequencer[] = TEXT("sequencer");
  127. SZCODE szVCR[] = TEXT("vcr");
  128. SZCODE szWaveAudio[] = TEXT("waveaudio");
  129. SZCODE szAVIVideo[] = TEXT("avivideo");
  130. STRING_TO_ID_MAP DevToDevIDMap[] =
  131. {
  132. { szCDAudio, DTMCI_CDAUDIO },
  133. { szVideoDisc, DTMCI_VIDEODISC },
  134. { szSequencer, DTMCI_SEQUENCER },
  135. { szVCR, DTMCI_VCR },
  136. { szWaveAudio, DTMCI_WAVEAUDIO },
  137. { szAVIVideo, DTMCI_AVIVIDEO }
  138. };
  139. void LoadStatusStrings(void);
  140. STATICFN BOOL NEAR PASCAL CheckErrorMCI(DWORD dwRet);
  141. extern LPTSTR FAR FileName(LPCTSTR szPath);
  142. HPALETTE CopyPalette(HPALETTE hpal);
  143. HANDLE PictureFromBitmap(HBITMAP hbm, HPALETTE hpal);
  144. HANDLE FAR PASCAL PictureFromDib(HANDLE hdib, HPALETTE hpal);
  145. HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal);
  146. LONG_PTR FAR PASCAL _EXPORT MCIWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  147. //
  148. // we will either send every command with a MCI_NOTIFY, or we will
  149. // not.
  150. //
  151. #define F_NOTIFY MCI_NOTIFY
  152. //#define F_NOTIFY 0
  153. BOOL FAR PASCAL InitMCI(HANDLE hPrev, HANDLE hInst)
  154. {
  155. if (!hPrev)
  156. {
  157. WNDCLASS cls;
  158. cls.lpszClassName = MCI_WINDOW_CLASS;
  159. cls.lpfnWndProc = (WNDPROC)MCIWndProc;
  160. cls.style = CS_HREDRAW | CS_VREDRAW | CS_SAVEBITS |
  161. CS_DBLCLKS;
  162. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  163. cls.hIcon = NULL;
  164. cls.lpszMenuName = NULL;
  165. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  166. cls.hInstance = hInst;
  167. cls.cbClsExtra = 0;
  168. cls.cbWndExtra = 0;
  169. if (!RegisterClass(&cls))
  170. return FALSE;
  171. }
  172. LoadStatusStrings();
  173. return TRUE;
  174. }
  175. /* LoadStatusStrings
  176. *
  177. * Fixes up the status-mapping table with pointers to strings loaded
  178. * from resources. This need be called only on initialisation.
  179. *
  180. * 2 February 1994, andrewbe, hardly at all based on the original.
  181. */
  182. void LoadStatusStrings(void)
  183. {
  184. int i;
  185. TCHAR Buffer[80];
  186. for( i = 0; i < sizeof(MCIStatusMapping) / sizeof(*MCIStatusMapping); i++ )
  187. {
  188. if( LOADSTRING( MCIStatusMapping[i].ResourceID, Buffer ) )
  189. {
  190. MCIStatusMapping[i].pString = AllocStr( Buffer );
  191. if( MCIStatusMapping[i].pString == NULL )
  192. {
  193. MCIStatusMapping[i].pString = szNULL;
  194. }
  195. }
  196. else
  197. {
  198. DPF0( "LoadStatusStrings failed to load string ID %d\n", MCIStatusMapping[i].ResourceID );
  199. MCIStatusMapping[i].pString = szNULL;
  200. }
  201. }
  202. }
  203. /* MapModeToStatusString
  204. *
  205. * Given an MCI mode, scans the mapping table to find the corresponding string.
  206. * In the event that an unknown mode is passed in (which shouldn't really happen),
  207. * the last string in the mapping table is returned.
  208. *
  209. * 2 February 1994, andrewbe
  210. */
  211. LPTSTR MapModeToStatusString( WORD Mode )
  212. {
  213. int i;
  214. for( i = 0; i < sizeof(MCIStatusMapping) / sizeof(*MCIStatusMapping); i++ )
  215. {
  216. if( MCIStatusMapping[i].Mode == Mode )
  217. {
  218. return MCIStatusMapping[i].pString;
  219. }
  220. }
  221. /* The following assumes that the last in the array of status mappings
  222. * contains a pointer to the "(unknown)" string:
  223. */
  224. return MCIStatusMapping[sizeof(MCIStatusMapping) / sizeof(*MCIStatusMapping) - 1].pString;
  225. }
  226. /******************************Public*Routine******************************\
  227. * IsCdromTrackAudio
  228. *
  229. * Filched from CD Player
  230. *
  231. \**************************************************************************/
  232. BOOL IsCdromTrackAudio(
  233. MCIDEVICEID DevHandle,
  234. int iTrackNumber)
  235. {
  236. MCI_STATUS_PARMS mciStatus;
  237. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  238. mciStatus.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
  239. mciStatus.dwTrack = iTrackNumber + 1;
  240. mciSendCommand( DevHandle, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
  241. (DWORD_PTR)(LPVOID)&mciStatus);
  242. return mciStatus.dwReturn == MCI_CDA_TRACK_AUDIO;
  243. }
  244. /* IsCdromDataOnly
  245. *
  246. * It seems that MCICDA can handle CDs with some audio tracks, so just check
  247. * whether there is at least one audio track.
  248. *
  249. */
  250. BOOL IsCdromDataOnly()
  251. {
  252. MCI_STATUS_PARMS mciStatus;
  253. DWORD dw;
  254. DWORD iTrack;
  255. DWORD_PTR NumTracks;
  256. /* gwNumTracks is set in UpdateMCI, but it hasn't been called
  257. * at this stage in the proceedings, and I'm not about to start
  258. * changing the order that things are done and bring this whole
  259. * flimsy edifice tumbling down.
  260. */
  261. ZeroMemory( &mciStatus, sizeof(mciStatus) );
  262. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  263. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  264. (DWORD_PTR)&mciStatus);
  265. /* Do NOT set gwNumtracks here, because this will result in an
  266. * access violation in CalcTicsOfDoom. What a nightmare!
  267. */
  268. NumTracks = mciStatus.dwReturn;
  269. /* If there was an error or there are no tracks, let's hope MCICDA
  270. * will throw a wobbly.
  271. */
  272. if (dw != 0 || NumTracks == 0)
  273. return FALSE;
  274. /* Now run through the tracks until we find an audio one:
  275. */
  276. for (iTrack = 0; iTrack < NumTracks - 1; iTrack++)
  277. {
  278. if (IsCdromTrackAudio(gwDeviceID, iTrack))
  279. return FALSE;
  280. }
  281. return TRUE;
  282. }
  283. #ifdef NEW_MCI_DIALOG
  284. //
  285. // Read the MCIAVI playback options from the registry
  286. //
  287. DWORD ReadOptionsFromReg(void)
  288. {
  289. HKEY hkVideoOpt;
  290. DWORD dwType;
  291. DWORD dwOpt;
  292. DWORD cbSize;
  293. if(RegCreateKey(HKEY_CURRENT_USER, (LPTSTR)aszMCIAVIOpt, &hkVideoOpt))
  294. return 0 ;
  295. cbSize = sizeof(DWORD);
  296. if (RegQueryValueEx(hkVideoOpt, (LPTSTR)aszDefVideoOpt, NULL, &dwType,
  297. (LPBYTE)&dwOpt,&cbSize ))
  298. {
  299. dwOpt = 0;
  300. RegSetValueEx(hkVideoOpt, (LPTSTR)aszDefVideoOpt, 0, REG_DWORD,
  301. (LPBYTE)&dwOpt, sizeof(DWORD));
  302. }
  303. RegCloseKey(hkVideoOpt);
  304. return dwOpt;
  305. }
  306. //
  307. // Obey the registry default sizing of Zoom by 2 and Fixed screen %. Takes the
  308. // registry values for MCIAVI and a rect, and either zooms it by 2 or replaces
  309. // it with a constant size or leaves it alone.
  310. //
  311. void FAR PASCAL AlterRectUsingDefaults(LPRECT lprc)
  312. {
  313. DWORD dwOptions;
  314. // This is only an MCIAVI hack.
  315. if ((gwDeviceType & DTMCI_DEVICE) != DTMCI_AVIVIDEO)
  316. return;
  317. dwOptions = ReadOptionsFromReg();
  318. if (dwOptions & MCIAVIO_ZOOMBY2)
  319. SetRect(lprc, 0, 0, lprc->right*2, lprc->bottom*2);
  320. else if (dwOptions & MCIAVIO_WINDOWSIZEMASK) {
  321. lprc->right = GetSystemMetrics (SM_CXSCREEN);
  322. lprc->bottom = GetSystemMetrics (SM_CYSCREEN);
  323. switch(dwOptions & MCIAVIO_WINDOWSIZEMASK)
  324. {
  325. case MCIAVIO_1QSCREENSIZE:
  326. SetRect(lprc, 0, 0, lprc->right/4, lprc->bottom/4);
  327. break;
  328. case MCIAVIO_2QSCREENSIZE:
  329. SetRect(lprc, 0, 0, lprc->right/2, lprc->bottom/2);
  330. break;
  331. case MCIAVIO_3QSCREENSIZE:
  332. SetRect(lprc, 0, 0, lprc->right*3/4, lprc->bottom*3/4);
  333. break;
  334. case MCIAVIO_MAXWINDOWSIZE:
  335. SetRect(lprc, 0, 0, lprc->right, lprc->bottom);
  336. break;
  337. }
  338. }
  339. }
  340. #endif /* NEW_MCI_DIALOG */
  341. /*
  342. * fOK = OpenMCI(szFile, szDevice)
  343. *
  344. * Open the file/device combination of <szFile> and <szDevice>.
  345. * <szFile> may be "" if a "pure device" (e.g. "CDAudio") is to be opened.
  346. * <szDevice> may be "" if a file is to be opened with an implicit type.
  347. * However, <szFile> and <szDevice> may not both be "".
  348. *
  349. * On success, return TRUE. On failure, display an error message and
  350. * return FALSE.
  351. *
  352. */
  353. BOOL FAR PASCAL OpenMCI(
  354. LPCTSTR szFile, /* name of the media file to be loaded (or "") */
  355. LPCTSTR szDevice) /* name of the device to be opened (or "") */
  356. {
  357. MCI_OPEN_PARMS mciOpen; /* Structure for MCI_OPEN command */
  358. DWORD dwFlags;
  359. DWORD dw;
  360. HCURSOR hcurPrev;
  361. HDRVR hdrv;
  362. SHFILEINFO sfi;
  363. HFILE hFile;
  364. /*
  365. * This application is designed to handle only one device at a time,
  366. * so before opening a new device we should close the device that is
  367. * currently open (if there is one).
  368. *
  369. * in case the user is opening a file of the same device again, do
  370. * an OpenDriver to hold the DLL in memory.
  371. *
  372. */
  373. if (gwDeviceID && gwCurDevice > 0) {
  374. #ifdef UNICODE
  375. hdrv = OpenDriver(garMciDevices[gwCurDevice].szDevice, aszMCI, 0);
  376. #else
  377. //
  378. // There is only a UNICODE version of OpenDriver. Unfortunately
  379. // the majority of this code is Ascii. Convert the ASCII strings
  380. // to UNICODE, then call OpenDriver
  381. //
  382. WCHAR waszMCI[sizeof(aszMCI)];
  383. WCHAR wszDevice[40];
  384. AnsiToUnicodeString(aszMCI, waszMCI, UNKNOWN_LENGTH);
  385. AnsiToUnicodeString(garMciDevices[gwCurDevice].szDevice, wszDevice, UNKNOWN_LENGTH);
  386. hdrv = OpenDriver((LPCWSTR)garMciDevices[gwCurDevice].szDevice,
  387. (LPCWSTR)aszMCI,
  388. 0);
  389. #endif
  390. }
  391. else
  392. hdrv = NULL;
  393. CloseMCI(TRUE);
  394. //
  395. // Store the displayable file/device name in <gachFileDevice>
  396. //
  397. if (szFile == NULL || szFile[0] == 0) {
  398. /* It's a device -- display the device name */
  399. lstrcpy(gachFileDevice, szDevice);
  400. if (gwCurDevice > 0)
  401. lstrcpy(gachWindowTitle,garMciDevices[gwCurDevice].szDeviceName);
  402. else
  403. lstrcpy(gachWindowTitle,gachFileDevice);
  404. } else {
  405. /* It's a file -- display the filename */
  406. lstrcpy(gachFileDevice, szFile); //!!!
  407. // Makes the window title be the name of the file being played
  408. lstrcpy(gachWindowTitle, FileName(gachFileDevice));
  409. }
  410. /* Get the display name for this file:
  411. */
  412. if (SHGetFileInfo(gachFileDevice, 0 /* No file attributes specified */,
  413. &sfi, sizeof sfi, SHGFI_DISPLAYNAME))
  414. lstrcpy(gachWindowTitle, sfi.szDisplayName);
  415. //
  416. // Set caption to the WindowTitle
  417. //
  418. lstrcpy(gachCaption, gachWindowTitle);
  419. /*
  420. * because *most* MCI devices yield during the open call, we *must*
  421. * register our document *before* doing the open. OLE does not expect
  422. * the server app to yield when exec'ed with a link request.
  423. *
  424. * if the open fails then we revoke our document right away.
  425. */
  426. // if (!gfEmbeddedObject)
  427. // RegisterDocument(0L,0L);
  428. /*
  429. * Show the hourglass cursor -- who knows how long this stuff
  430. * will take
  431. */
  432. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  433. DPF("OpenMCI: Device = %"DTS", File = %"DTS"\n", szDevice ? szDevice : TEXT("(null)"),szFile ? szFile : TEXT("(null)"));
  434. mciOpen.lpstrAlias = aszMPlayerAlias;
  435. dwFlags = MCI_OPEN_ALIAS;
  436. if (szFile == NULL || szFile[0] == 0) {
  437. /* Open a fileless (simple) device (e.g. "CDAudio") */
  438. mciOpen.lpstrDeviceType = szDevice;
  439. dwFlags |= MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE;
  440. } else if (szDevice == NULL || szDevice[0] == 0) {
  441. /*
  442. * Open a file; the correct device is determined implicitly by the
  443. * filename extension.
  444. *
  445. */
  446. mciOpen.lpstrElementName = szFile;
  447. mciOpen.lpstrDeviceType = NULL;
  448. dwFlags |= MCI_WAIT | MCI_OPEN_ELEMENT;
  449. } else {
  450. /* Open a file with an explicitly specified device */
  451. mciOpen.lpstrDeviceType = szDevice;
  452. mciOpen.lpstrElementName = szFile;
  453. dwFlags |= MCI_WAIT | MCI_OPEN_ELEMENT | MCI_OPEN_TYPE;
  454. }
  455. /*
  456. * Now that we have filled the parameter structure appropriately and
  457. * supplied the correct flags, send the actual MCI_OPEN message.
  458. *
  459. */
  460. //
  461. // What if the MCI device brings up an error box! We don't want MPlayer
  462. // to be allowed to exit.
  463. //
  464. gfErrorBox++;
  465. dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, dwFlags,(DWORD_PTR)(LPVOID)&mciOpen);
  466. if (dw != 0 && (dwFlags & MCI_OPEN_SHAREABLE))
  467. dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, (dwFlags & ~MCI_OPEN_SHAREABLE),
  468. (DWORD_PTR)(LPVOID)&mciOpen);
  469. DPF("MCI_OPEN returned %lu, wDeviceID=%u\n", dw, mciOpen.wDeviceID);
  470. gfErrorBox--;
  471. /*
  472. * now free the driver instance we opened above.
  473. */
  474. if (hdrv)
  475. CloseDriver(hdrv, 0, 0);
  476. if (hcurPrev)
  477. SetCursor(hcurPrev);
  478. if (dw != 0 && !gfEmbeddedObject) {
  479. // UnblockServer(); // we may have blocked before and the error
  480. // recovery code will loop infinitely if we're
  481. // blocked!
  482. InitDoc(TRUE);
  483. }
  484. /* If the open was unsuccessful, display an error message and return */
  485. if (dw == MCIERR_DEVICE_OPEN || /* nonshareable device already open */
  486. dw == MCIERR_MUST_USE_SHAREABLE) {
  487. Error(ghwndApp, IDS_DEVICEINUSE);
  488. return FALSE;
  489. }
  490. if (dw == MCIERR_FILE_NOT_FOUND) {
  491. //Need to give an appropriate error message.
  492. //The following could be the causes:
  493. //1. File does not exist
  494. //This is already handled by the file open dialog box.
  495. //2. Access to the file is denied. (bug #53492)
  496. //3. The file is opened exclusively by another app.
  497. //The file already exists. so if it cannot be opened for reading
  498. //either access is denied or it is opened by another app.
  499. if ((hFile = (HFILE)HandleToUlong(CreateFile (szFile, GENERIC_READ,
  500. FILE_SHARE_READ, NULL,
  501. OPEN_EXISTING, 0, NULL))) == HFILE_ERROR)
  502. {
  503. Error(ghwndApp, IDS_CANTACCESSFILE);
  504. }
  505. //4. File was not in a recognized format
  506. else
  507. {
  508. _lclose(hFile);
  509. Error(ghwndApp, IDS_CANTOPENFILE);
  510. }
  511. return FALSE;
  512. }
  513. /* If the MCI device that plays the given file does not exist then */
  514. /* bring up a dialog box and close mplayer. */
  515. if (dw == MCIERR_INVALID_DEVICE_NAME) {
  516. Error(ghwndApp, IDS_DEVICENOTINSTALLED);
  517. return FALSE;
  518. }
  519. if (dw != 0) { /* some other error */
  520. //
  521. // try again, if we can't open the file with a particular device.
  522. // this lets the MCI core try to figure out the device type from
  523. // the file extension, or some other method.
  524. //
  525. if ((dw != MCIERR_DRIVER_INTERNAL) && szDevice != NULL &&
  526. szDevice[0] != 0) {
  527. if (szFile && szFile[0] != 0) {
  528. return OpenMCI(szFile, TEXT(""));
  529. }
  530. }
  531. CheckErrorMCI(dw);
  532. return FALSE;
  533. }
  534. /* The open was successful, so retain the MCI device ID for later use */
  535. gwDeviceID = (UINT)mciOpen.wDeviceID;
  536. //
  537. // now query the device and see what it can do
  538. //
  539. FindDeviceMCI();
  540. gwDeviceType = QueryDeviceTypeMCI(gwDeviceID);
  541. if (!(gwDeviceType & DTMCI_CANPLAY)) {
  542. Error(ghwndApp, IDS_DEVICECANNOTPLAY);
  543. CloseMCI(TRUE);
  544. return FALSE;
  545. }
  546. if (!(gwDeviceType & (DTMCI_TIMEMS|DTMCI_TIMEFRAMES))) {
  547. Error(ghwndApp, IDS_NOGOODTIMEFORMATS);
  548. CloseMCI(TRUE);
  549. return FALSE;
  550. }
  551. if (gwDeviceType & DTMCI_CANWINDOW) {
  552. GetDestRectMCI(&grcSize);
  553. #ifdef NEW_MCI_DIALOG
  554. grcInitSize = grcSize;
  555. // HACK!! We want to pay attention to some MCIAVI registry default
  556. // sizes, so we'll read the registry and adjust the size of the movie
  557. // accordingly.
  558. AlterRectUsingDefaults(&grcSize);
  559. #endif /* NEW_MCI_DIALOG */
  560. } else
  561. SetRectEmpty(&grcSize);
  562. if (IsRectEmpty(&grcSize)) {
  563. DPF("NULL rectange in GetDestRect() assuming device cant window!\n");
  564. gwDeviceType &= ~DTMCI_CANWINDOW;
  565. }
  566. /* Turn on the update-display timer so the display is updated regularly */
  567. EnableTimer(TRUE);
  568. /*
  569. ** for devices that do windows, show the window right away.
  570. **
  571. ** !!! note when we support a built in window it will go here.
  572. */
  573. if (gfPlayOnly) {
  574. CreateWindowMCI();
  575. if (!IsIconic(ghwndApp))
  576. SetMPlayerSize(&grcSize);
  577. }
  578. else if (GetWindowMCI() && IsWindowVisible(ghwndApp)) {
  579. MCI_SEEK_PARMS mciSeek; /* parameter structure for MCI_SEEK */
  580. TCHAR achReturn[40];
  581. PostMessage(ghwndApp, WM_QUERYNEWPALETTE, 0, 0);
  582. //
  583. // make sure the default window is the right size.
  584. //
  585. PutWindowMCI(NULL);
  586. //
  587. // center the default window above or below our window
  588. //
  589. SmartWindowPosition(GetWindowMCI(), ghwndApp, TRUE);
  590. //
  591. // make sure the default window is showing
  592. //
  593. ShowWindowMCI(TRUE);
  594. /* hack for MMP, do a seek to the start, it does not paint
  595. correctly for some reason if we just show the window!
  596. NOTE: 0 may not be the start of the media so this may
  597. fail, but OH WELL! We can't call UpdateMCI yet to set
  598. gdwMediaStart because we don't know the scale (time/frames)
  599. yet so UpdateMCI won't set gdwMediaLength properly, and
  600. I don't feel like calling UpdateMCI twice, so tough!!
  601. And we can't just SeekMCI(0) because UpdateDisplay will get
  602. called too soon so we hack everything! */
  603. mciSendString(aszInfoProduct, achReturn,
  604. CHAR_COUNT(achReturn), NULL);
  605. if (!lstrcmpi(achReturn, aszMMPName)) {
  606. mciSeek.dwTo = 0;
  607. dw = mciSendCommand(gwDeviceID, MCI_SEEK, MCI_TO,
  608. (DWORD_PTR)&mciSeek);
  609. }
  610. }
  611. /*
  612. * Remember to update the media information and the caption when
  613. * UpdateDisplay() is next called. We don't set them until now
  614. * because we want the ReadDefaults() to be called which will set
  615. * gwCurScale to happen before UpdateDisplay calls UpdateMCI.
  616. */
  617. gfValidMediaInfo = FALSE;
  618. gfValidCaption = FALSE;
  619. return TRUE;
  620. }
  621. //
  622. // GetDeviceNameMCI()
  623. //
  624. // wLen is the size IN BYTES of szDevice buffer
  625. void FAR PASCAL GetDeviceNameMCI(LPTSTR szDevice, UINT wLen)
  626. {
  627. MCI_SYSINFO_PARMS mciSysInfo;
  628. DWORD dw;
  629. //
  630. // assume failure.
  631. //
  632. szDevice[0] = 0;
  633. mciSysInfo.dwCallback = 0L;
  634. mciSysInfo.lpstrReturn = szDevice;
  635. mciSysInfo.dwRetSize = wLen;
  636. mciSysInfo.dwNumber = 0;
  637. mciSysInfo.wDeviceType = 0;
  638. if (gwDeviceID) {
  639. dw = mciSendCommand(gwDeviceID, MCI_SYSINFO,
  640. MCI_SYSINFO_INSTALLNAME,
  641. (DWORD_PTR)(LPVOID)&mciSysInfo);
  642. }
  643. }
  644. //
  645. // QueryDevicesMCI
  646. //
  647. // wLen is the size IN BYTES of szDevice buffer
  648. //
  649. // Returns a list of devices in form "<device1>\0<device2>\0 ... <deviceN>\0\0"
  650. void FAR PASCAL QueryDevicesMCI(LPTSTR szDevices, UINT wLen)
  651. {
  652. MCI_SYSINFO_PARMS mciSysInfo;
  653. DWORD dw;
  654. DWORD i;
  655. DWORD_PTR cDevices; /* Total number of devices to enumerate */
  656. DWORD BufferPos; /* Index to end of buffer */
  657. //
  658. // assume failure.
  659. //
  660. szDevices[0] = 0;
  661. szDevices[1] = 0;
  662. mciSysInfo.dwCallback = 0L;
  663. mciSysInfo.lpstrReturn = szDevices;
  664. mciSysInfo.dwRetSize = wLen;
  665. mciSysInfo.dwNumber = 0;
  666. mciSysInfo.wDeviceType = MCI_ALL_DEVICE_ID;
  667. /* How many devices does mmsystem know about?
  668. */
  669. dw = mciSendCommand(MCI_ALL_DEVICE_ID,
  670. MCI_SYSINFO,
  671. MCI_SYSINFO_QUANTITY,
  672. (DWORD_PTR)(LPVOID)&mciSysInfo);
  673. if (dw == 0) {
  674. /* Device count is returned in lpstrReturn!
  675. */
  676. cDevices = (DWORD_PTR)(LPVOID)*mciSysInfo.lpstrReturn;
  677. BufferPos = 0;
  678. /* Get the name of each device in turn. N.B. Not zero-based!
  679. * Ensure there's room for the final (double) null terminator.
  680. */
  681. for (i = 1; i < (cDevices + 1) && BufferPos < (wLen - 1); i++) {
  682. mciSysInfo.lpstrReturn = &(szDevices[BufferPos]);
  683. mciSysInfo.dwRetSize = wLen - BufferPos; /* How much space left */
  684. mciSysInfo.dwNumber = i;
  685. dw = mciSendCommand(MCI_ALL_DEVICE_ID,
  686. MCI_SYSINFO,
  687. MCI_SYSINFO_NAME,
  688. (DWORD_PTR)(LPVOID)&mciSysInfo);
  689. if (dw == 0) {
  690. DPF1("Found device: %"DTS"\n", &(szDevices[BufferPos]));
  691. BufferPos += (lstrlen(&(szDevices[BufferPos])) + 1);
  692. }
  693. }
  694. /* Not strictly required, since our buffer was allocated LMEM_ZEROINIT:
  695. */
  696. szDevices[BufferPos] = '\0';
  697. }
  698. }
  699. //
  700. // FindDeviceMCI()
  701. //
  702. // Find the device the user just opened. We normally should know what
  703. // was opened, but in the auto-open case MCI will pick a device for us.
  704. //
  705. // Determines what device is associated with <gwDeviceID> and
  706. // sets the <gwCurDevice> global.
  707. //
  708. // Called by OpenMCI() whenever a new device is opened successfully.
  709. //
  710. void FAR PASCAL FindDeviceMCI(void)
  711. {
  712. UINT w;
  713. TCHAR achDevice[80];
  714. //
  715. // assume failure.
  716. //
  717. gwCurDevice = 0;
  718. GetDeviceNameMCI(achDevice, BYTE_COUNT(achDevice));
  719. for (w=1; w<=gwNumDevices; w++)
  720. {
  721. if (lstrcmpi(achDevice, garMciDevices[w].szDevice) == 0) {
  722. gwCurDevice = w;
  723. }
  724. if (ghMenu)
  725. CheckMenuItem(ghMenu, IDM_DEVICE0+w, MF_BYCOMMAND |
  726. ((gwCurDevice == w) ? MF_CHECKED : MF_UNCHECKED));
  727. }
  728. if (gwCurDevice == 0)
  729. {
  730. DPF("FindDevice: Unable to find device\n");
  731. }
  732. }
  733. void FAR PASCAL CreateWindowMCI()
  734. {
  735. RECT rc;
  736. HWND hwnd;
  737. if (IsWindow(ghwndMCI) || !gwDeviceID || !(gwDeviceType & DTMCI_CANWINDOW))
  738. return;
  739. /* Figure out how big the Playback window is, and make our MCI window */
  740. /* the same size. */
  741. hwnd = GetWindowMCI();
  742. if (hwnd != NULL)
  743. GetClientRect(hwnd, &rc);
  744. else
  745. rc = grcSize; // use original size if error
  746. CreateWindowEx(gfdwFlagsEx,
  747. MCI_WINDOW_CLASS,
  748. TEXT(""),
  749. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  750. rc.left,
  751. rc.top,
  752. rc.right - rc.left,
  753. rc.bottom - rc.top,
  754. ghwndApp,
  755. (HMENU)NULL,
  756. ghInst,
  757. NULL);
  758. }
  759. /*
  760. * SendStringMCI() - send a MCI string command to the device.
  761. *
  762. * the string is of the form "verb params" our device name is inserted
  763. * after the verb and sent to the device.
  764. *
  765. */
  766. DWORD PASCAL SendStringMCI(PTSTR szCmd, PTSTR szReturn, UINT wLen /* Characters */)
  767. {
  768. TCHAR ach[MCI_STRING_LENGTH + CHAR_COUNT(aszMPlayerAlias) + 1];
  769. TCHAR *pch;
  770. pch = ach;
  771. while (*szCmd && *szCmd != TEXT(' '))
  772. *pch++ = *szCmd++;
  773. *pch++ = TEXT(' ');
  774. lstrcpy(pch,aszMPlayerAlias);
  775. lstrcat(pch,szCmd);
  776. return mciSendString(ach, szReturn, wLen, ghwndApp);
  777. }
  778. /*
  779. * UpdateMCI()
  780. *
  781. * Update <gfCanEject>, <gdwMediaLength>, <gwNumTracks>, and <gadwTrackStart>
  782. * to agree with what MCI knows them to be.
  783. */
  784. void FAR PASCAL UpdateMCI(void)
  785. {
  786. MCI_STATUS_PARMS mciStatus; /* Structure for MCI_STATUS command */
  787. DWORD dw;
  788. HCURSOR hcurPrev;
  789. if (gfValidMediaInfo)
  790. return;
  791. /* If no device is currently open, then there's nothing to update */
  792. if (gwDeviceID == (UINT)0) {
  793. return;
  794. }
  795. /*
  796. * Show the hourglass cursor -- who knows how long this stuff will take
  797. */
  798. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  799. /*
  800. * This function may fail (due to I/O error etc.), but we might as
  801. * well say that the media information is valid now, because otherwise
  802. * we'll just get into an endless loop.
  803. *
  804. */
  805. gfValidMediaInfo = TRUE;
  806. gdwMediaStart = 0L;
  807. gdwMediaLength = 0L;
  808. gwNumTracks = 0;
  809. /* If things aren't valid anyway, give up. */
  810. if (gwStatus == MCI_MODE_OPEN || gwStatus == MCI_MODE_NOT_READY)
  811. goto exit;
  812. /* Find out how many tracks are present in the medium */
  813. mciStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
  814. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  815. (DWORD_PTR)&mciStatus);
  816. #ifdef DEBUG
  817. DPF("MCI_STATUS (MCI_STATUS_NUMBER_OF_TRACKS) returned %lu,"
  818. " %d tracks\n", dw, mciStatus.dwReturn);
  819. #endif
  820. /*
  821. * If the command retuned a value of zero, then the medium contains tracks,
  822. * so use the number of tracks returned in the parameter structure.
  823. * Otherwise, the medium does not contain tracks, so use a value of 0.
  824. *
  825. */
  826. if (dw == 0L)
  827. gwNumTracks = (UINT) mciStatus.dwReturn;
  828. /* Set the correct time format either frames or milliseconds */
  829. if (gwCurScale == ID_FRAMES && !(gwDeviceType & DTMCI_TIMEFRAMES))
  830. gwCurScale = ID_TIME;
  831. if (gwCurScale == ID_TRACKS && gwNumTracks <= 1)
  832. gwCurScale = ID_TIME;
  833. if (gwCurScale == ID_TIME && !(gwDeviceType & DTMCI_TIMEMS))
  834. gwCurScale = ID_FRAMES;
  835. /* set the time format, If this does not work, punt. */
  836. if (!SetTimeFormatMCI(gwCurScale == ID_FRAMES ? MCI_FORMAT_FRAMES : MCI_FORMAT_MILLISECONDS))
  837. goto exit;
  838. mciStatus.dwItem = MCI_STATUS_LENGTH;
  839. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  840. (DWORD_PTR)&mciStatus);
  841. DPF("MCI_STATUS (MCI_STATUS_LENGTH) returned %lu, media length %ld\n", dw, mciStatus.dwReturn);
  842. /*
  843. * If the MCI command returned a nonzero value, then an error has
  844. * occurred, so alert the user, close the offending device, and return.
  845. *
  846. */
  847. if (dw != 0L)
  848. goto exit;
  849. /* Everything is OK, so retain the media length for later use */
  850. gdwMediaLength = (DWORD)mciStatus.dwReturn;
  851. mciStatus.dwItem = MCI_STATUS_POSITION;
  852. dw = mciSendCommand(gwDeviceID, MCI_STATUS,
  853. MCI_STATUS_START | MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
  854. #ifdef DEBUG
  855. DPF2("MCI_STATUS (MCI_STATUS_START) returned %lu, start %ld\n",dw, mciStatus.dwReturn);
  856. #endif
  857. gdwMediaStart = (DWORD)mciStatus.dwReturn;
  858. if (dw != 0) {
  859. /* Error: forget about track display */
  860. gwNumTracks = 0;
  861. }
  862. if (gwNumTracks > 0) {
  863. UINT wTrack;
  864. /* Free the track map if it already exists */
  865. if (gadwTrackStart != NULL)
  866. FreeMem(gadwTrackStart, sizeof(DWORD) * gwNumTracks);
  867. /* Allocate memory for the track map */
  868. gadwTrackStart = AllocMem(sizeof(DWORD) * gwNumTracks);
  869. if (gadwTrackStart == NULL) {
  870. /* AllocMem() failed - alert the user, close the device, return */
  871. Error(ghwndApp, IDS_OUTOFMEMORY);
  872. gwNumTracks = 0;
  873. goto exit;
  874. }
  875. /* See if there is a track zero */
  876. mciStatus.dwItem = MCI_STATUS_POSITION;
  877. mciStatus.dwTrack = (DWORD) 0;
  878. dw = mciSendCommand(gwDeviceID, MCI_STATUS,
  879. MCI_TRACK | MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
  880. #ifdef DEBUG
  881. DPF2("MCI_STATUS (MCI_STATUS_START for track %lu) returned %lu, start %ld\n", mciStatus.dwTrack, dw, mciStatus.dwReturn);
  882. #endif
  883. if (dw == 0)
  884. gwFirstTrack = 0;
  885. else
  886. gwFirstTrack = 1;
  887. /* Get the track map from MCI */
  888. for (wTrack = 0; wTrack < gwNumTracks; wTrack++) {
  889. mciStatus.dwItem = MCI_STATUS_POSITION;
  890. mciStatus.dwTrack = (DWORD) wTrack + gwFirstTrack;
  891. dw = mciSendCommand(gwDeviceID, MCI_STATUS,
  892. MCI_TRACK | MCI_STATUS_ITEM, (DWORD_PTR)&mciStatus);
  893. #ifdef DEBUG
  894. DPF2("MCI_STATUS (MCI_STATUS_START for track %lu) returned %lu, start %ld\n", mciStatus.dwTrack, dw,mciStatus.dwReturn);
  895. #endif
  896. if (dw != 0) {
  897. #if 1
  898. /* Error: forget about track display */
  899. gwNumTracks = 0;
  900. goto exit;
  901. #else
  902. /* An error occurred - do the usual stuff */
  903. Error(ghwndApp, IDS_CANTACCESSFILEDEV);
  904. goto exit;
  905. #endif
  906. }
  907. /* Add the start of this track to the track list */
  908. gadwTrackStart[wTrack] = (DWORD)mciStatus.dwReturn;
  909. }
  910. }
  911. /*
  912. * Invalidate the track map window so it will be redrawn with the
  913. * correct positions, etc.
  914. *
  915. */
  916. exit:
  917. #ifdef DEBUG
  918. DPF("Finished updating status: # tracks = %u, length = %lu\n", gwNumTracks, gdwMediaLength);
  919. #endif
  920. SendMessage(ghwndTrackbar, TBM_SETRANGEMIN, (WPARAM)FALSE, gdwMediaStart);
  921. SendMessage(ghwndTrackbar, TBM_SETRANGEMAX, (WPARAM)FALSE, gdwMediaStart + gdwMediaLength);
  922. /* We must set the range before calling TBM_SETTIC (which is sent by
  923. * CalcTicsOfDoom()), since the common trackbar now tests the range
  924. * before accepting a new tic.
  925. * It would probably be better to set the range in CalcTicsOfDoom().
  926. */
  927. if (!gfCurrentCDNotAudio)
  928. CalcTicsOfDoom();
  929. SendMessage(ghwndTrackbar, TBM_SETSELSTART, (WPARAM)FALSE, -1); // invalid selection
  930. SendMessage(ghwndTrackbar, TBM_SETSELEND, (WPARAM)TRUE, -1);
  931. if (hcurPrev)
  932. SetCursor(hcurPrev);
  933. }
  934. /*
  935. * CloseMCI(fUpdateDisplay)
  936. *
  937. * Close the currently-open MCI device (if any). If <fUpdateDisplay>
  938. * is TRUE, then update the display as well.
  939. *
  940. * Closing the device merely relinquishes control of it so that the device
  941. * may be used by someone else. The device does not necessarily stop playing
  942. * or return to the start of the medium when this message is received - the
  943. * behaviour is device-dependent.
  944. *
  945. */
  946. void FAR PASCAL CloseMCI(BOOL fUpdateDisplay)
  947. {
  948. DWORD dw;
  949. UINT w;
  950. HWND hwnd;
  951. if (!gfEmbeddedObject)
  952. gachCaption[0] = 0; // nuke the caption
  953. /* If no device is currently open, then there's nothing to close */
  954. if (gwDeviceID == (UINT)0)
  955. return;
  956. /*
  957. * Disable the display-update timer, as there's no longer any reason to
  958. * periodically update the display.
  959. */
  960. EnableTimer(FALSE);
  961. ////StopMCI();
  962. //
  963. // set either the owner or the WS_CHILD bit so it will
  964. // not act up because we have the palette bit set and cause the
  965. // desktop to steal the palette.
  966. //
  967. // because we are being run from client apps that dont deal
  968. // with palettes we dont want the desktop to hose the palette.
  969. //
  970. hwnd = GetWindowMCI();
  971. if ((hwnd != NULL) && gfRunWithEmbeddingFlag)
  972. SetParent(hwnd, ghwndApp);
  973. /* Send the MCI CLOSE message, and set the current device to NULL */
  974. dw = mciSendCommand(gwDeviceID, MCI_CLOSE, 0L, (DWORD_PTR)0);
  975. gwDeviceID = (UINT)0;
  976. gwDeviceType = 0;
  977. gwCurScale = ID_NONE;
  978. SetRectEmpty(&grcSize);
  979. /* Now close the MCI window AFTER we close the MCIDevice, so that the */
  980. /* SetMCIWindow(NULL) this does won't flash up a default playback win.*/
  981. if (ghwndMCI) {
  982. /*
  983. ** Don't pass the WM_CLOSE to the subclass window proc or it will
  984. ** spuriously issue and IDM_CLOSE again!
  985. */
  986. if (gfnMCIWndProc != NULL && ghwndSubclass == ghwndMCI) {
  987. SetWindowLongPtr(ghwndMCI, GWLP_WNDPROC, (LONG_PTR)gfnMCIWndProc);
  988. gfnMCIWndProc = NULL;
  989. }
  990. SendMessage(ghwndMCI, WM_CLOSE, 0, 0L);
  991. }
  992. /* Don't set gwCurDevice = 0 because if we were called by Open MCI, then */
  993. /* we won't remember what device we were opening. So instead, we'll set */
  994. /* gwCurDevice = 0 after returning from CloseMCI if we so desire. I know*/
  995. /* it sounds hacky, but Todd told me to do it this way. End disclamer. */
  996. /* Uncheck the device menus */
  997. if (ghMenu) {
  998. for (w = 1; w <= gwNumDevices; w++)
  999. CheckMenuItem(ghMenu, IDM_DEVICE0 + w, MF_BYCOMMAND | MF_UNCHECKED);
  1000. }
  1001. DPF("MCI_CLOSE returned %lu\n", dw);
  1002. /* Free up the resources used by the track map */
  1003. if (gadwTrackStart != NULL)
  1004. {
  1005. FreeMem(gadwTrackStart, sizeof(DWORD) * gwNumTracks);
  1006. gadwTrackStart = NULL;
  1007. }
  1008. /* If you have auto-repeat on and you load a new file in between the */
  1009. /* repeating, the new file may come up with no buttons or no scrollbar */
  1010. /* because our JustPlayed code sets the old status to PLAY which avoids*/
  1011. /* updating. */
  1012. gfJustPlayed = FALSE;
  1013. /*
  1014. * If the display update flag was set, then update the display, taking
  1015. * into account that the media information and caption are now inaccurate.
  1016. */
  1017. if (fUpdateDisplay) {
  1018. gfValidCaption = FALSE;
  1019. gfValidMediaInfo = FALSE;
  1020. UpdateDisplay();
  1021. }
  1022. }
  1023. /* Helper function to check return code from MCI functions. */
  1024. STATICFN BOOL NEAR PASCAL CheckErrorMCI(DWORD dwRet)
  1025. {
  1026. TCHAR ach[200];
  1027. if (dwRet != 0 && dwRet != MCIERR_NONAPPLICABLE_FUNCTION) {
  1028. mciGetErrorString(dwRet, ach, CHAR_COUNT(ach));
  1029. Error1(ghwndApp, IDS_DEVICEERROR, ach);
  1030. // CloseMCI(TRUE);
  1031. return FALSE;
  1032. }
  1033. return TRUE;
  1034. }
  1035. /*
  1036. * PlayMCI()
  1037. *
  1038. * Start the current device playing. If the device is in a paused state,
  1039. * un-pause it.
  1040. * Maybe play the selection.
  1041. *
  1042. #ifdef NEW_MCI_DIALOG
  1043. * NOTE: MCIAVI will automatically play fullscreen if that option is selected
  1044. * in the registry. We don't have to do anything.
  1045. #endif NEW_MCI_DIALOG
  1046. *
  1047. */
  1048. BOOL FAR PASCAL PlayMCI(DWORD_PTR dwFrom, DWORD_PTR dwTo)
  1049. {
  1050. MCI_PLAY_PARMS mciPlay; /* structure used to pass parameters along
  1051. with the MCI_PLAY command */
  1052. DWORD dw; /* variable holding the return value of
  1053. the various MCI commands */
  1054. DWORD dwflags = 0L; /* play flags */
  1055. /* If no device is currently open, then there's nothing to play */
  1056. DPF("mciPlay: From=%d To=%d\n", dwFrom, dwTo);
  1057. if (gwDeviceID == (UINT)0)
  1058. return TRUE;
  1059. if (gfInPlayMCI) {
  1060. return(TRUE);
  1061. }
  1062. gfInPlayMCI = TRUE;
  1063. /*
  1064. * Send the MCI_PLAY message. This will start the device playing from
  1065. * wherever the current position is within the medium. This message will
  1066. * un-pause the player if it is currently in the paused state.
  1067. *
  1068. */
  1069. mciPlay.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1070. if (dwFrom != dwTo) {
  1071. mciPlay.dwFrom = (DWORD)dwFrom;
  1072. mciPlay.dwTo = (DWORD)dwTo;
  1073. dwflags = MCI_FROM | MCI_TO;
  1074. }
  1075. /* don't allow MCIAVI full screen mode --- force Windowing */
  1076. if (gfPlayingInPlace && ((gwDeviceType & DTMCI_DEVICE) == DTMCI_AVIVIDEO))
  1077. dwflags |= MCI_MCIAVI_PLAY_WINDOW;
  1078. /* If auto-repeat is on, MCIAVI will bring the playback window to the */
  1079. /* front every time it repeats, because that's what it does when you */
  1080. /* issue a play. To avoid that, we'll just do a play repeat once. */
  1081. if (((gwDeviceType & DTMCI_DEVICE) == DTMCI_AVIVIDEO) &&
  1082. (gwOptions & OPT_AUTOREP))
  1083. dwflags |= MCI_DGV_PLAY_REPEAT;
  1084. //
  1085. // what if the MCI device brings up a error box? We don't want MPlayer
  1086. // to be allowed to exit.
  1087. //
  1088. gfErrorBox++;
  1089. dw = mciSendCommand(gwDeviceID, MCI_PLAY, F_NOTIFY | dwflags, (DWORD_PTR)&mciPlay);
  1090. DPF("MCI_PLAY returned %lu\n", dw);
  1091. gfErrorBox--;
  1092. /* In case it stops so soon we wouldn't notice this play command. */
  1093. if (dw == 0)
  1094. gfJustPlayed = TRUE;
  1095. gfInPlayMCI = FALSE;
  1096. return CheckErrorMCI(dw);
  1097. }
  1098. /*
  1099. * SetTimeFormatMCI()
  1100. *
  1101. * sets the current time format
  1102. *
  1103. */
  1104. BOOL FAR PASCAL SetTimeFormatMCI(UINT wTimeFormat)
  1105. {
  1106. MCI_SET_PARMS mciSet; /* Structure for MCI_SET command */
  1107. DWORD dw;
  1108. mciSet.dwTimeFormat = wTimeFormat;
  1109. dw = mciSendCommand(gwDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
  1110. (DWORD_PTR) (LPVOID) &mciSet);
  1111. if (dw != 0) {
  1112. mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  1113. mciSendCommand(gwDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
  1114. (DWORD_PTR)(LPVOID)&mciSet);
  1115. }
  1116. return (dw == 0);
  1117. }
  1118. /*
  1119. * PauseMCI()
  1120. *
  1121. * Pause the current MCI device.
  1122. *
  1123. */
  1124. BOOL FAR PASCAL PauseMCI(void)
  1125. {
  1126. MCI_GENERIC_PARMS mciGeneric; /* General-purpose structure used to pass
  1127. parameters along with various MCI
  1128. commands */
  1129. DWORD dw; /* variable holding the return value of
  1130. the various MCI commands */
  1131. /* If no device is currently open, then there's nothing to pause */
  1132. if (gwDeviceID == (UINT)0)
  1133. return TRUE;
  1134. /* Send the MCI_PAUSE message */
  1135. mciGeneric.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1136. dw = mciSendCommand(gwDeviceID, MCI_PAUSE, F_NOTIFY, (DWORD_PTR)&mciGeneric);
  1137. DPF("MCI_PAUSE returned %lu\n", dw);
  1138. if (dw == MCIERR_UNSUPPORTED_FUNCTION) {
  1139. /* Pause isn't supported. Don't allow it any more. */
  1140. gwDeviceType &= ~DTMCI_CANPAUSE;
  1141. }
  1142. return CheckErrorMCI(dw);
  1143. }
  1144. /*
  1145. * SeekExactMCI()
  1146. *
  1147. * Set set exactly on or off
  1148. *
  1149. */
  1150. BOOL FAR PASCAL SeekExactMCI(BOOL fExact)
  1151. {
  1152. DWORD dw;
  1153. BOOL fWasExact;
  1154. MCI_STATUS_PARMS mciStatus;
  1155. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANSEEKEXACT))
  1156. return FALSE;
  1157. //
  1158. // see if the device can seek exactly
  1159. //
  1160. dw = mciSendString(aszSeekExact, NULL, 0, NULL);
  1161. if (dw != 0)
  1162. {
  1163. gwDeviceType &= ~DTMCI_CANSEEKEXACT;
  1164. return FALSE;
  1165. }
  1166. //
  1167. // get current value.
  1168. //
  1169. mciStatus.dwItem = MCI_DGV_STATUS_SEEK_EXACTLY;
  1170. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  1171. (DWORD_PTR) (LPVOID) &mciStatus);
  1172. fWasExact = (dw == 0 && mciStatus.dwReturn != MCI_OFF) ? TRUE : FALSE;
  1173. if (fExact)
  1174. dw = mciSendString(aszSeekExactOn, NULL, 0, NULL);
  1175. else
  1176. dw = mciSendString(aszSeekExactOff, NULL, 0, NULL);
  1177. return fWasExact;
  1178. }
  1179. /*
  1180. * SetAudioMCI()
  1181. *
  1182. * Set audio for the current MCI device on/off.
  1183. *
  1184. */
  1185. BOOL FAR PASCAL SetAudioMCI(BOOL fAudioOn)
  1186. {
  1187. MCI_SET_PARMS mciSet;
  1188. DWORD dw;
  1189. /* If no device is currently open, then there's nothing to do. */
  1190. if (gwDeviceID == (UINT)0)
  1191. return TRUE;
  1192. /* Send the MCI_SET message */
  1193. mciSet.dwAudio = MCI_SET_AUDIO_ALL;
  1194. dw = mciSendCommand(gwDeviceID, MCI_SET,
  1195. MCI_SET_AUDIO | (fAudioOn ? MCI_SET_ON : MCI_SET_OFF),
  1196. (DWORD_PTR)&mciSet);
  1197. DPF("MCI_SET returned %lu\n", dw);
  1198. return CheckErrorMCI(dw);
  1199. }
  1200. /*
  1201. * StopMCI()
  1202. *
  1203. * Stop the current MCI device.
  1204. *
  1205. */
  1206. BOOL FAR PASCAL StopMCI(void)
  1207. {
  1208. MCI_GENERIC_PARMS mciGeneric; /* General-purpose structure used to pass
  1209. parameters along with various MCI
  1210. commands */
  1211. DWORD dw; /* variable holding the return value of
  1212. the various MCI commands */
  1213. /* If no device is currently open, then there's nothing to stop */
  1214. if (gwDeviceID == (UINT)0)
  1215. return TRUE;
  1216. /* Send the MCI_STOP message */
  1217. mciGeneric.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1218. dw = mciSendCommand(gwDeviceID, MCI_STOP, F_NOTIFY,
  1219. (DWORD_PTR)&mciGeneric);
  1220. DPF("MCI_STOP returned %lu\n", dw);
  1221. return CheckErrorMCI(dw);
  1222. }
  1223. /*
  1224. * EjectMCI(fOpen)
  1225. *
  1226. * Open the device door if <fOpen> is TRUE, otherwise close it.
  1227. *
  1228. * To do: When un-ejected, update track map, media length, etc.
  1229. *
  1230. */
  1231. BOOL FAR PASCAL EjectMCI(BOOL fOpen)
  1232. {
  1233. MCI_GENERIC_PARMS mciGeneric; /* General-purpose structure used to pass
  1234. parameters along with various MCI
  1235. commands */
  1236. DWORD dw; /* variable holding the return value of
  1237. the various MCI commands */
  1238. /* If no device is currently open, then there's nothing to eject */
  1239. if (gwDeviceID == (UINT)0)
  1240. return TRUE;
  1241. /*
  1242. * Send a message opening or closing the door depending on the state of
  1243. * <fOpen>.
  1244. *
  1245. */
  1246. mciGeneric.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1247. dw = mciSendCommand(gwDeviceID, MCI_SET,
  1248. (fOpen ? MCI_SET_DOOR_OPEN : MCI_SET_DOOR_CLOSED) | F_NOTIFY,
  1249. (DWORD_PTR)&mciGeneric);
  1250. DPF("MCI_SET (MCI_SET_DOOR_%s) returned %lu\n",(LPSTR)(fOpen ? "OPEN" : "CLOSED"), dw);
  1251. return CheckErrorMCI(dw);
  1252. }
  1253. /*
  1254. * SeekMCI(dwPosition)
  1255. *
  1256. * Seek to position <dwPosition> (measured in milliseconds from 0L to
  1257. * <gdwMediaLength> inclusive).
  1258. *
  1259. */
  1260. STATICDT BOOL sfSeeking = FALSE;
  1261. BOOL FAR PASCAL SeekMCI(DWORD_PTR dwPosition)
  1262. {
  1263. DWORD dw; /* variable holding the return value of
  1264. the various MCI commands */
  1265. static int wStatus = -1;
  1266. /*
  1267. * If no device is currently open, then there's not much bloody point
  1268. * in trying to seek to a new position, is there?
  1269. *
  1270. */
  1271. if (gwDeviceID == (UINT)0)
  1272. return TRUE;
  1273. /*
  1274. ** If we're seeking, decide whether to play from or seek to based on
  1275. ** the status at the last time we seeked. Otherwise, use the current
  1276. ** status.
  1277. */
  1278. if (!sfSeeking)
  1279. wStatus = gwStatus;
  1280. /* Playing from end of media is broken in CD, so don't let it happen. */
  1281. if (dwPosition >= gdwMediaStart + gdwMediaLength) {
  1282. if (!StopMCI())
  1283. return FALSE;
  1284. wStatus = MCI_MODE_STOP;
  1285. }
  1286. if (wStatus == MCI_MODE_PLAY) {
  1287. MCI_PLAY_PARMS mciPlay; /* parameter structure for MCI_PLAY */
  1288. DWORD dwflags = 0L;
  1289. /*
  1290. * If the player in in 'Play' mode, then we want to jump to the new
  1291. * position and keep playing. This can be done by sending an MCI_PLAY
  1292. * message and specifying the position which we wish to play from.
  1293. *
  1294. */
  1295. mciPlay.dwFrom = (DWORD)dwPosition;
  1296. mciPlay.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1297. /* don't allow MCIAVI full screen mode --- force Windowing */
  1298. if (gfPlayingInPlace && ((gwDeviceType & DTMCI_DEVICE) == DTMCI_AVIVIDEO))
  1299. dwflags |= MCI_MCIAVI_PLAY_WINDOW;
  1300. dw = mciSendCommand(gwDeviceID, MCI_PLAY, MCI_FROM | F_NOTIFY | dwflags,
  1301. (DWORD_PTR)&mciPlay);
  1302. DPF("MCI_PLAY (from %lu) returned %lu\n", mciPlay.dwFrom, dw);
  1303. /* In case it stops so soon we wouldn't notice this play command. */
  1304. if (dw == 0)
  1305. gfJustPlayed = TRUE;
  1306. }
  1307. else {
  1308. MCI_SEEK_PARMS mciSeek; /* parameter structure for MCI_SEEK */
  1309. /*
  1310. * In any other state but 'Play', we want the player to go to the new
  1311. * position and remain stopped. This is accomplished by sending an
  1312. * MCI_SEEK message and specifying the position we want to seek to.
  1313. *
  1314. */
  1315. mciSeek.dwTo = (DWORD)dwPosition;
  1316. mciSeek.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1317. dw = mciSendCommand(gwDeviceID, MCI_SEEK, MCI_TO | F_NOTIFY,
  1318. (DWORD_PTR)&mciSeek);
  1319. DPF2("MCI_SEEK (to %lu) returned %lu\n", mciSeek.dwTo, dw);
  1320. }
  1321. /*
  1322. * If no error occurred, save the position that is to be seeked to in
  1323. * order to use that position in UpdateDisplay() if the device is in
  1324. * seek mode.
  1325. *
  1326. */
  1327. if (!dw)
  1328. gdwLastSeekToPosition = (DWORD)dwPosition;
  1329. /*
  1330. * Because we've moved to a new position in the medium, the scrollbar
  1331. * thumb is no longer positioned accurately. Call UpdateDisplay()
  1332. * immediately to rectify this. (We could just wait for the next
  1333. * automatic update, but this is friendlier).
  1334. *
  1335. */
  1336. UpdateDisplay();
  1337. return CheckErrorMCI(dw);
  1338. }
  1339. /* SeekToStartMCI( )
  1340. *
  1341. * Better than SeekMCI(gdwMediaStart) for CDAudio (like, it works).
  1342. *
  1343. */
  1344. BOOL FAR PASCAL SeekToStartMCI( )
  1345. {
  1346. MCI_SEEK_PARMS mciSeek; /* parameter structure for MCI_SEEK */
  1347. DWORD dw;
  1348. mciSeek.dwTo = 0;
  1349. mciSeek.dwCallback = (DWORD_PTR)(HWND) ghwndApp;
  1350. dw = mciSendCommand(gwDeviceID, MCI_SEEK, MCI_SEEK_TO_START,
  1351. (DWORD_PTR)&mciSeek);
  1352. DPF2("MCI_SEEK_TO_START returned %lu\n", dw);
  1353. return CheckErrorMCI(dw);
  1354. }
  1355. /*
  1356. * SkipTrackMCI(iSkip)
  1357. *
  1358. * Skip to the beginning of track <iCur> + <iSkip>, where <iCur>
  1359. * is the current track.
  1360. *
  1361. */
  1362. void FAR PASCAL SkipTrackMCI(int iSkip)
  1363. {
  1364. MCI_STATUS_PARMS mciStatus; /* Structure used to pass parameters
  1365. along with an MCI_STATUS command */
  1366. DWORD dw; /* variable holding the return value
  1367. of the various MCI commands */
  1368. int iTrack; /* index of the track to skip to */
  1369. static int iLastTrack = -1;
  1370. /* If no device is currently open, then return */
  1371. if (gwDeviceID == (UINT)0)
  1372. return;
  1373. /* Determine the track # of the current track */
  1374. if (gfScrollTrack && gdwSeekPosition != 0) {
  1375. iTrack = iLastTrack + iSkip;
  1376. } else {
  1377. mciStatus.dwItem = MCI_STATUS_CURRENT_TRACK;
  1378. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  1379. (DWORD_PTR)&mciStatus);
  1380. DPF("MCI_STATUS (MCI_STATUS_CURRENT_TRACK) returned %lu, current track %ld\n", dw, mciStatus.dwReturn);
  1381. if (dw != 0L) {
  1382. /* Something went wrong, but it isn't catastrophic... */
  1383. MessageBeep(0);
  1384. return;
  1385. }
  1386. /* Compute the track # to which we wish to skip */
  1387. iTrack = ((int) mciStatus.dwReturn) + iSkip;
  1388. }
  1389. /* Handle special case of seeking backward from middle first track */
  1390. if (iTrack < (int)gwFirstTrack)
  1391. iTrack = (int)gwFirstTrack;
  1392. /* Don't do anything if <iTrack> is out of range */
  1393. if ((iTrack < (int)gwFirstTrack) || (iTrack >= (int)gwNumTracks +
  1394. (int)gwFirstTrack))
  1395. return;
  1396. /* Everything seems to be OK, so skip to the requested track */
  1397. gdwSeekPosition = gadwTrackStart[iTrack - gwFirstTrack];
  1398. iLastTrack = iTrack;
  1399. /* Hack: Update global scroll position */
  1400. SendMessage(ghwndTrackbar, TBM_SETPOS, TRUE, gadwTrackStart[iTrack-gwFirstTrack]);
  1401. }
  1402. STATICFN DWORD GetMode(MCI_STATUS_PARMS *pmciStatus)
  1403. {
  1404. pmciStatus->dwItem = MCI_STATUS_MODE;
  1405. if (0 != mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  1406. (DWORD_PTR)pmciStatus)) {
  1407. /* If the command returned a nonzero value, the mode is unknown */
  1408. return MCI_MODE_NOT_READY;
  1409. } else {
  1410. return (UINT)pmciStatus->dwReturn;
  1411. }
  1412. }
  1413. /*
  1414. * wStatus = StatusMCI(pdwPosition)
  1415. *
  1416. * Query the status of the current device and return it.
  1417. *
  1418. * If <pdwPosition> is not NULL, then <*pdwPosition> is filled in with
  1419. * the current position of the device within the medium (in milliseconds,
  1420. * from 0 to <gdwMediaLength> *inclusive*). <*pdwPosition> is not
  1421. * necessarily filled in if MCI_MODE_NOT_READY is returned.
  1422. *
  1423. */
  1424. UINT FAR PASCAL StatusMCI(DWORD_PTR* pdwPosition)
  1425. {
  1426. static UINT swModeLast = MCI_MODE_NOT_READY;
  1427. MCI_STATUS_PARMS mciStatus;
  1428. DWORD dw;
  1429. UINT wMode;
  1430. DWORD dwPosition;
  1431. /* If no device is currently open, return error. */
  1432. if (gwDeviceID == (UINT)0)
  1433. return MCI_MODE_NOT_READY;
  1434. /* Determine what the current mode (status) of the device is */
  1435. wMode = GetMode(&mciStatus);
  1436. if ((gwDeviceType & DTMCI_CANPLAY) &&
  1437. wMode != MCI_MODE_OPEN && wMode != MCI_MODE_NOT_READY) {
  1438. /* Determine the current position within the medium */
  1439. mciStatus.dwItem = MCI_STATUS_POSITION;
  1440. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  1441. (DWORD_PTR)&mciStatus);
  1442. DPF4("position = %lu (%lu)\n", mciStatus.dwReturn, dw);
  1443. /* If an error occurred, set the current position to zero */
  1444. if (dw == 0)
  1445. dwPosition = (DWORD)mciStatus.dwReturn;
  1446. else
  1447. dwPosition = 0L;
  1448. } else
  1449. dwPosition = 0L;
  1450. /*
  1451. * If the current position is past the end of the medium, set it to be
  1452. * equal to the end of the medium.
  1453. *
  1454. */
  1455. if (dwPosition > gdwMediaLength + gdwMediaStart) {
  1456. DPF("Position beyond end of media: truncating value\n");
  1457. dwPosition = gdwMediaLength + gdwMediaStart;
  1458. }
  1459. if (dwPosition < gdwMediaStart) {
  1460. DPF2("Position before beginning of media: adjusting value\n");
  1461. dwPosition = gdwMediaStart;
  1462. }
  1463. sfSeeking = (wMode == MCI_MODE_SEEK);
  1464. /*
  1465. * If we were passed a valid position pointer, then return the current
  1466. * position.
  1467. *
  1468. */
  1469. if (pdwPosition != NULL)
  1470. *pdwPosition = dwPosition;
  1471. /* Return the status of the device */
  1472. return wMode;
  1473. }
  1474. /*
  1475. * wRet = QueryDeviceTypeMCI(wDeviceID)
  1476. *
  1477. * This routine determines whether or not the device given in <szDevice> uses
  1478. * files and whether or not it can play anything at all.
  1479. * It does so by opening the device in question and then querying its
  1480. * capabilities.
  1481. *
  1482. * It returns a combination of DTMCI_ flags or DTMCI_ERROR
  1483. *
  1484. */
  1485. UINT FAR PASCAL QueryDeviceTypeMCI(UINT wDeviceID)
  1486. {
  1487. MCI_GETDEVCAPS_PARMS mciDevCaps; /* for the MCI_GETDEVCAPS command */
  1488. MCI_SET_PARMS mciSet; /* for the MCI_SET command */
  1489. MCI_ANIM_WINDOW_PARMS mciWindow; /* for the MCI_WINDOW command */
  1490. DWORD dw;
  1491. UINT wRet=0;
  1492. TCHAR achDevice[40];
  1493. DWORD i;
  1494. //
  1495. // determine if the device is simple or compound
  1496. //
  1497. mciDevCaps.dwItem = MCI_GETDEVCAPS_COMPOUND_DEVICE;
  1498. dw = mciSendCommand(wDeviceID, MCI_GETDEVCAPS,
  1499. MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps);
  1500. DPF("MCI_GETDEVCAPS_COMPOUND_DEVICE: %lu (ret=%lu)\n", dw, mciDevCaps.dwReturn);
  1501. if (dw == 0 && mciDevCaps.dwReturn != 0)
  1502. wRet |= DTMCI_COMPOUNDDEV;
  1503. else
  1504. wRet |= DTMCI_SIMPLEDEV;
  1505. //
  1506. // determine if the device handles files
  1507. //
  1508. if (wRet & DTMCI_COMPOUNDDEV) {
  1509. mciDevCaps.dwItem = MCI_GETDEVCAPS_USES_FILES;
  1510. dw = mciSendCommand(wDeviceID, MCI_GETDEVCAPS,
  1511. MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps);
  1512. DPF("MCI_GETDEVCAPS_USES_FILES: %lu (ret=%lu)\n", dw, mciDevCaps.dwReturn);
  1513. if (dw == 0 && mciDevCaps.dwReturn != 0)
  1514. wRet |= DTMCI_FILEDEV;
  1515. }
  1516. //
  1517. // determine if the device can play
  1518. //
  1519. mciDevCaps.dwItem = MCI_GETDEVCAPS_CAN_PLAY;
  1520. dw = mciSendCommand(wDeviceID, MCI_GETDEVCAPS,
  1521. MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps);
  1522. if (dw == 0 && mciDevCaps.dwReturn != 0)
  1523. wRet |= DTMCI_CANPLAY;
  1524. //
  1525. // determine if the device can pause
  1526. //
  1527. if (wRet & DTMCI_CANPLAY)
  1528. wRet |= DTMCI_CANPAUSE; // assume it can pause!!!
  1529. //
  1530. // determine if the device does frames
  1531. //
  1532. mciSet.dwTimeFormat = MCI_FORMAT_FRAMES;
  1533. dw = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSet);
  1534. DPF("MCI_SET TIME FORMAT (frames) returned %lu\n", dw);
  1535. if (dw == 0)
  1536. wRet |= DTMCI_TIMEFRAMES;
  1537. //
  1538. // determine if the device does milliseconds
  1539. //
  1540. mciSet.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
  1541. dw = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSet);
  1542. DPF("MCI_SET TIME FORMAT (milliseconds) returned %lu\n", dw);
  1543. if (dw == 0)
  1544. wRet |= DTMCI_TIMEMS;
  1545. //
  1546. // determine if the device can eject.
  1547. //
  1548. mciDevCaps.dwItem = MCI_GETDEVCAPS_CAN_EJECT;
  1549. dw = mciSendCommand(wDeviceID, MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM, (DWORD_PTR)(LPVOID)&mciDevCaps);
  1550. DPF("MCI_GETDEVCAPS (MCI_GETDEVCAPS_CAN_EJECT) returned %lu, can eject: %ld\n", dw, mciDevCaps.dwReturn);
  1551. if (dw == 0 && mciDevCaps.dwReturn)
  1552. wRet |= DTMCI_CANEJECT;
  1553. //
  1554. // determine if the device supports configuration
  1555. //
  1556. dw = mciSendCommand(wDeviceID, MCI_CONFIGURE, MCI_TEST, (DWORD_PTR)NULL);
  1557. DPF("MCI_CONFIGURE (MCI_TEST) returned %lu\n", dw);
  1558. if (dw == 0)
  1559. wRet |= DTMCI_CANCONFIG;
  1560. //
  1561. // test the device driver and see if it can config.
  1562. //
  1563. if (!(wRet & DTMCI_CANCONFIG)) {
  1564. //!!! is this safe?
  1565. dw = mciSendCommand(wDeviceID, DRV_QUERYCONFIGURE, 0, 0);
  1566. if (dw == 1L)
  1567. wRet |= DTMCI_CANCONFIG;
  1568. }
  1569. //
  1570. // determine if the device supports the "set audio" command
  1571. //
  1572. mciSet.dwAudio = MCI_SET_AUDIO_ALL;
  1573. dw = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_AUDIO | MCI_SET_ON,(DWORD_PTR)(LPVOID)&mciSet);
  1574. DPF("MCI_SET (audio all) returned %lu\n", dw);
  1575. if (dw == 0)
  1576. wRet |= DTMCI_CANMUTE;
  1577. //
  1578. // determine if the device supports the "window" command, by sending a
  1579. // "window handle default" command
  1580. //
  1581. #ifdef NEWSTUFF
  1582. /* Uh oh, we don't want to do this, because it causes our MCIWnd to be
  1583. * overridden by the default window:
  1584. */
  1585. if (MCIWndCanWindow(ghwndMCI) == TRUE);
  1586. wRet |= DTMCI_CANWINDOW;
  1587. #else
  1588. mciWindow.hWnd = MCI_ANIM_WINDOW_DEFAULT;
  1589. dw = mciSendCommand(wDeviceID, MCI_WINDOW,MCI_ANIM_WINDOW_HWND|MCI_WAIT,
  1590. (DWORD_PTR)(LPVOID)&mciWindow);
  1591. DPF("MCI_WINDOW: (set default) dw=0x%08lx\n", dw);
  1592. if (dw == 0)
  1593. wRet |= DTMCI_CANWINDOW;
  1594. //
  1595. // determine if the device supports the "window" command, by sending a
  1596. // "window state hide" command
  1597. //
  1598. if (!(wRet & DTMCI_CANWINDOW)) {
  1599. mciWindow.nCmdShow = SW_HIDE;
  1600. dw = mciSendCommand(wDeviceID, MCI_WINDOW,MCI_ANIM_WINDOW_STATE|MCI_WAIT,
  1601. (DWORD_PTR)(LPVOID)&mciWindow);
  1602. DPF("MCI_WINDOW: (hide) dw=0x%08lx\n", dw);
  1603. if (dw == 0)
  1604. wRet |= DTMCI_CANWINDOW;
  1605. }
  1606. #endif /* NEWSTUFF */
  1607. //
  1608. // assume the device can seek exact.
  1609. //
  1610. wRet |= DTMCI_CANSEEKEXACT; // assume it can seek exact
  1611. //
  1612. // Are we the MCIAVI device?
  1613. //
  1614. GetDeviceNameMCI(achDevice, BYTE_COUNT(achDevice));
  1615. if (*achDevice)
  1616. {
  1617. for (i = 0; i < sizeof DevToDevIDMap / sizeof *DevToDevIDMap; i++)
  1618. {
  1619. if (!lstrcmpi(achDevice, DevToDevIDMap[i].pString))
  1620. {
  1621. wRet |= DevToDevIDMap[i].ID;
  1622. DPF("Found device %"DTS"\n", DevToDevIDMap[i].pString);
  1623. break;
  1624. }
  1625. }
  1626. }
  1627. mciDevCaps.dwItem = MCI_GETDEVCAPS_DEVICE_TYPE;
  1628. dw = mciSendCommand(gwDeviceID, MCI_GETDEVCAPS,
  1629. MCI_GETDEVCAPS_ITEM, (DWORD_PTR)&mciDevCaps);
  1630. if ((dw == 0)
  1631. &&(mciDevCaps.dwReturn == MCI_DEVTYPE_CD_AUDIO))
  1632. wRet |= DTMCI_CDAUDIO;
  1633. return wRet;
  1634. }
  1635. BOOL FAR PASCAL SetWindowMCI(HWND hwnd)
  1636. {
  1637. MCI_ANIM_WINDOW_PARMS mciWindow; /* for the MCI_WINDOW command */
  1638. DWORD dw;
  1639. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))
  1640. return FALSE;
  1641. mciWindow.hWnd = hwnd;
  1642. dw = mciSendCommand(gwDeviceID, MCI_WINDOW,MCI_ANIM_WINDOW_HWND|MCI_WAIT,
  1643. (DWORD_PTR)(LPVOID)&mciWindow);
  1644. if (dw != 0)
  1645. gwDeviceType &= ~DTMCI_CANWINDOW;
  1646. return (dw == 0);
  1647. }
  1648. BOOL FAR PASCAL ShowWindowMCI(BOOL fShow)
  1649. {
  1650. DWORD dw;
  1651. if (fShow)
  1652. dw = mciSendString(aszWindowShow, NULL, 0, NULL);
  1653. else
  1654. dw = mciSendString(aszWindowHide, NULL, 0, NULL);
  1655. return dw == 0;
  1656. }
  1657. BOOL FAR PASCAL PutWindowMCI(LPRECT prc)
  1658. {
  1659. RECT rc;
  1660. HWND hwnd;
  1661. UINT w;
  1662. //
  1663. // note we could use the "put window at x y dx dy client" command but it
  1664. // may not work on all devices.
  1665. //
  1666. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))
  1667. return FALSE;
  1668. if (!(hwnd = GetWindowMCI()))
  1669. return FALSE;
  1670. //
  1671. // either snap to the default size or use the given size *and* position.
  1672. //
  1673. if (prc == NULL || IsRectEmpty(prc))
  1674. rc = grcSize;
  1675. else
  1676. rc = *prc;
  1677. if (rc.left == 0 && rc.top == 0)
  1678. w = SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE;
  1679. else
  1680. w = SWP_NOZORDER | SWP_NOACTIVATE;
  1681. AdjustWindowRect(&rc, (DWORD)GetWindowLongPtr(hwnd, GWL_STYLE), GetMenu(hwnd) != NULL);
  1682. SetWindowPos(hwnd, NULL, rc.left, rc.top, rc.right-rc.left,
  1683. rc.bottom-rc.top,w);
  1684. return TRUE;
  1685. }
  1686. HWND FAR PASCAL GetWindowMCI(void)
  1687. {
  1688. DWORD dw;
  1689. TCHAR ach[40];
  1690. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))
  1691. return NULL;
  1692. dw = mciSendString(aszStatusWindow, ach, CHAR_COUNT(ach), NULL);
  1693. if (dw != 0)
  1694. gwDeviceType &= ~DTMCI_CANWINDOW;
  1695. if (dw == 0)
  1696. return (HWND)IntToPtr(ATOI(ach));
  1697. else
  1698. return NULL;
  1699. }
  1700. BOOL FAR PASCAL SetPaletteMCI(HPALETTE hpal)
  1701. {
  1702. MCI_DGV_SETVIDEO_PARMS mciVideo;
  1703. DWORD dw;
  1704. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))
  1705. return FALSE;
  1706. //!!! bug should not send this.
  1707. mciVideo.dwItem = MCI_DGV_SETVIDEO_PALHANDLE;
  1708. mciVideo.dwValue = (DWORD)(DWORD_PTR)(UINT_PTR)hpal;
  1709. dw = mciSendCommand(gwDeviceID, MCI_SETVIDEO,
  1710. MCI_DGV_SETVIDEO_ITEM|MCI_DGV_SETVIDEO_VALUE|MCI_WAIT,
  1711. (DWORD_PTR)(LPVOID)&mciVideo);
  1712. return (dw == 0);
  1713. }
  1714. /*
  1715. * wRet = DeviceTypeMCI(szDevice)
  1716. *
  1717. * This routine determines whether or not the device given in <szDevice> uses
  1718. * files and whether or not it can play anything at all.
  1719. * It does so by opening the device in question and then querying its
  1720. * capabilities. It returns either DTMCI_FILEDEV, DTMCI_SIMPLEDEV,
  1721. * DTMCI_CANTPLAY, or DTMCI_ERROR.
  1722. *
  1723. */
  1724. UINT FAR PASCAL DeviceTypeMCI(
  1725. LPTSTR szDevice, /* name of the device to be opened (or "") */
  1726. LPTSTR szDeviceName, /* place to put device full-name */
  1727. int nBuf) /* size of buffer IN CHARACTERS */
  1728. {
  1729. MCI_OPEN_PARMS mciOpen; /* Structure used for MCI_OPEN */
  1730. MCI_INFO_PARMS mciInfo; /* Structure used for MCI_INFO */
  1731. DWORD dw;
  1732. UINT wRet;
  1733. if (szDeviceName && nBuf > 0)
  1734. szDeviceName[0] = 0;
  1735. /*
  1736. * Open the device as a simple device. If the device is actually compound,
  1737. * then the open should still succeed, but the only thing we'll be able to
  1738. * go is query the device capabilities.
  1739. */
  1740. mciOpen.lpstrDeviceType = szDevice;
  1741. dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, MCI_OPEN_TYPE,(DWORD_PTR)&mciOpen);
  1742. if (dw == MCIERR_MUST_USE_SHAREABLE)
  1743. dw = mciSendCommand((MCIDEVICEID)0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE,
  1744. (DWORD_PTR)(LPVOID)&mciOpen);
  1745. DPF("MCI_OPEN(%"DTS") returned %lu, wDeviceID=%u\n", szDevice, dw, mciOpen.wDeviceID);
  1746. /* If the open was unsuccessful, return */
  1747. switch (dw)
  1748. {
  1749. case MCIERR_MUST_USE_SHAREABLE:
  1750. case MCIERR_DEVICE_OPEN:
  1751. return DTMCI_IGNOREDEVICE;
  1752. case 0: // no error
  1753. break;
  1754. default:
  1755. DPF("Unable to open device (%"DTS")\n", szDevice);
  1756. return DTMCI_ERROR;
  1757. }
  1758. wRet = QueryDeviceTypeMCI(mciOpen.wDeviceID);
  1759. //
  1760. // get the "name" of the device if the caller wants it
  1761. //
  1762. if (szDeviceName && nBuf > 0)
  1763. {
  1764. mciInfo.dwCallback = 0;
  1765. mciInfo.lpstrReturn = szDeviceName;
  1766. mciInfo.dwRetSize = nBuf;
  1767. //
  1768. // default the product name to the device name
  1769. //
  1770. lstrcpy(szDeviceName, szDevice);
  1771. dw = mciSendCommand(mciOpen.wDeviceID, MCI_INFO,
  1772. MCI_INFO_PRODUCT, (DWORD_PTR)(LPVOID)&mciInfo);
  1773. if (dw != 0)
  1774. lstrcpy(szDeviceName, szDevice);
  1775. }
  1776. /* Close the device, and exit */
  1777. dw = mciSendCommand(mciOpen.wDeviceID, MCI_CLOSE, 0L, (DWORD_PTR)0);
  1778. return wRet;
  1779. }
  1780. BOOL FAR PASCAL ConfigMCI(HWND hwnd)
  1781. {
  1782. DWORD dw;
  1783. DRVCONFIGINFO drvc;
  1784. RECT rc1,rc2;
  1785. #ifndef UNICODE
  1786. WCHAR waszMCI[sizeof(aszMCI)];
  1787. WCHAR wszDevice[40];
  1788. #endif
  1789. if (gwDeviceID == (UINT)0)
  1790. return TRUE;
  1791. dw = mciSendCommand(gwDeviceID, MCI_CONFIGURE, MCI_TEST, (DWORD_PTR)0);
  1792. if (dw == 0) {
  1793. GetDestRectMCI(&rc1);
  1794. dw = mciSendCommand(gwDeviceID, MCI_CONFIGURE, 0L, (DWORD_PTR)0);
  1795. GetDestRectMCI(&rc2);
  1796. //
  1797. // get the new size from MCIAVI, because the user may have
  1798. // chosen ZoomBy2 as default.
  1799. //
  1800. //
  1801. // This won't happen anymore... it was fixed by an MCIAVI fix.
  1802. //
  1803. #ifdef NEW_MCI_DIALOG
  1804. if (IsRectEmpty(&rc2))
  1805. {
  1806. /* On Windows 95, GetDestRectMCI() returns an empty rectangle
  1807. * if you make a change in the configure dialog.
  1808. * I don't know if this is a bug.
  1809. */
  1810. grcSize = grcInitSize;
  1811. AlterRectUsingDefaults(&grcSize);
  1812. SetDestRectMCI(&grcSize);
  1813. SetMPlayerSize(&grcSize);
  1814. //HACK: It doesn't always repaint properly.
  1815. InvalidateRect(GetWindowMCI(), NULL, TRUE);
  1816. }
  1817. else
  1818. #endif
  1819. if (!EqualRect(&rc1, &rc2) && !IsRectEmpty(&rc2))
  1820. grcSize = rc2;
  1821. } else if (dw != MCIERR_DEVICE_NOT_READY) {
  1822. drvc.dwDCISize = sizeof(drvc);
  1823. #ifdef UNICODE
  1824. drvc.lpszDCISectionName = aszMCI;
  1825. drvc.lpszDCIAliasName = garMciDevices[gwCurDevice].szDevice;
  1826. dw = mciSendCommand(gwDeviceID, DRV_CONFIGURE, (LONG_PTR) (UINT_PTR) hwnd,
  1827. (DWORD_PTR) (DRVCONFIGINFO FAR *) &drvc);
  1828. #else
  1829. // No ASCII->Unicode thunking exists for DRV_CONFIGURE. We have
  1830. // to pass unicode strings on the configure command.
  1831. AnsiToUnicodeString(aszMCI, waszMCI, UNKNOWN_LENGTH);
  1832. AnsiToUnicodeString(garMciDevices[gwCurDevice].szDevice, wszDevice, UNKNOWN_LENGTH);
  1833. drvc.lpszDCISectionName = waszMCI;
  1834. drvc.lpszDCIAliasName = wszDevice;
  1835. #ifdef CHICAGO_PRODUCT
  1836. dw = mciSendCommand(gwDeviceID, DRV_CONFIGURE, (LONG) (UINT) hwnd,
  1837. (DWORD_PTR) (DRVCONFIGINFO FAR *) &drvc);
  1838. #else
  1839. dw = mciSendCommandW(gwDeviceID, DRV_CONFIGURE, (LONG) (UINT) hwnd,
  1840. (DWORD_PTR) (DRVCONFIGINFO FAR *) &drvc);
  1841. #endif
  1842. #endif
  1843. }
  1844. return dw == 0;
  1845. }
  1846. BOOL FAR PASCAL GetDestRectMCI(LPRECT lprc)
  1847. {
  1848. MCI_ANIM_RECT_PARMS mciRect;
  1849. DWORD dw;
  1850. /* get the size (rectangle) of the element */
  1851. if (gwDeviceID != (UINT)0)
  1852. dw = mciSendCommand(gwDeviceID, MCI_WHERE,
  1853. MCI_ANIM_WHERE_DESTINATION | MCI_WAIT,
  1854. (DWORD_PTR)(LPVOID)&mciRect);
  1855. else
  1856. dw = 1;
  1857. DPF("MCI_WHERE (dest): dw0x%08lx [%d,%d,%d,%d]\n", dw, mciRect.rc);
  1858. if (dw != 0) {
  1859. SetRectEmpty(lprc);
  1860. return FALSE;
  1861. }
  1862. else {
  1863. *lprc = mciRect.rc;
  1864. lprc->right += lprc->left;
  1865. lprc->bottom += lprc->top;
  1866. return TRUE;
  1867. }
  1868. }
  1869. #if 0 /* This is never called */
  1870. BOOL FAR PASCAL GetSourceRectMCI(LPRECT lprc)
  1871. {
  1872. MCI_ANIM_RECT_PARMS mciRect;
  1873. DWORD dw;
  1874. /* get the size (rectangle) of the element */
  1875. if (gwDeviceID != (UINT)0)
  1876. dw = mciSendCommand(gwDeviceID, MCI_WHERE,
  1877. MCI_ANIM_WHERE_SOURCE | MCI_WAIT,
  1878. (DWORD_PTR)(LPVOID)&mciRect);
  1879. else
  1880. dw = 1;
  1881. DPF("MCI_WHERE (source): dw0x%08lx [%d,%d,%d,%d]\n", dw, mciRect.rc);
  1882. if (dw != 0) {
  1883. SetRectEmpty(lprc);
  1884. return FALSE;
  1885. }
  1886. else {
  1887. *lprc = mciRect.rc;
  1888. lprc->right += lprc->left;
  1889. lprc->bottom += lprc->top;
  1890. return TRUE;
  1891. }
  1892. }
  1893. #endif
  1894. BOOL FAR PASCAL SetDestRectMCI(LPRECT lprc)
  1895. {
  1896. MCI_ANIM_RECT_PARMS mciRect;
  1897. DWORD dw;
  1898. mciRect.rc = *lprc;
  1899. /* get the size (rectangle) of the element */
  1900. mciRect.rc.right = mciRect.rc.right - mciRect.rc.left;
  1901. mciRect.rc.bottom = mciRect.rc.bottom - mciRect.rc.top;
  1902. dw = mciSendCommand(gwDeviceID, MCI_PUT,
  1903. MCI_ANIM_RECT | MCI_ANIM_PUT_DESTINATION | MCI_WAIT,
  1904. (DWORD_PTR)(LPVOID)&mciRect);
  1905. if (dw != 0)
  1906. {
  1907. DPF0("mciSendCommand( MCI_PUT ) failed with error x%08x\n", dw);
  1908. }
  1909. DPF("MCI_PUT (dest): [%d,%d,%d,%d]\n", mciRect.rc);
  1910. return (dw == 0);
  1911. }
  1912. #if 0
  1913. BOOL FAR PASCAL SetSourceRectMCI(LPRECT lprc)
  1914. {
  1915. MCI_ANIM_RECT_PARMS mciRect;
  1916. DWORD dw;
  1917. mciRect.rc = *lprc;
  1918. mciRect.rc.right = mciRect.rc.right - mciRect.rc.left;
  1919. mciRect.rc.bottom = mciRect.rc.bottom - mciRect.rc.top;
  1920. dw = mciSendCommand(gwDeviceID, MCI_PUT,
  1921. MCI_ANIM_RECT | MCI_ANIM_PUT_SOURCE | MCI_WAIT,
  1922. (DWORD_PTR)(LPVOID)&mciRect);
  1923. DPF("MCI_PUT (source): [%d,%d,%d,%d]\n", mciRect.rc);
  1924. return (dw == 0);
  1925. }
  1926. #endif
  1927. HPALETTE FAR PASCAL PaletteMCI(void)
  1928. {
  1929. MCI_STATUS_PARMS mciStatus;
  1930. DWORD dw;
  1931. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW))
  1932. return NULL;
  1933. mciStatus.dwItem = MCI_ANIM_STATUS_HPAL;
  1934. dw = mciSendCommand(gwDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
  1935. (DWORD_PTR)(LPVOID)&mciStatus);
  1936. if (dw == 0 && mciStatus.dwReturn)
  1937. return (HPALETTE)mciStatus.dwReturn;
  1938. else
  1939. return NULL;
  1940. }
  1941. HBITMAP FAR PASCAL BitmapMCI(void)
  1942. {
  1943. MCI_ANIM_UPDATE_PARMS mciUpdate;
  1944. HDC hdc, hdcMem;
  1945. HBITMAP hbm, hbmT;
  1946. HBRUSH hbrOld;
  1947. HANDLE hfontOld;
  1948. DWORD dw;
  1949. RECT rc;
  1950. int xExt, yExt; // size of text area
  1951. int xOff = 0, yOff = 0; // offset of text string
  1952. int xSize, ySize; // size of whole picture
  1953. int xIconOffset; // x Offset if drawing Icon.
  1954. TCHAR ach[20];
  1955. RECT rcSave;
  1956. RECT rcs;
  1957. SIZE TempSize;
  1958. /* Minimum size of bitmap is icon size */
  1959. int ICON_MINX = GetSystemMetrics(SM_CXICON);
  1960. int ICON_MINY = GetSystemMetrics(SM_CYICON);
  1961. /* Get size of a frame or an icon that we'll be drawing */
  1962. rcs = grcSize;
  1963. GetDestRectMCI(&grcSize);
  1964. rc = grcSize;
  1965. if (IsRectEmpty(&rc))
  1966. SetRect(&rc, 0, 0, 3*ICON_MINX, ICON_MINY);
  1967. /* Offset to title bar */
  1968. yOff = rc.bottom;
  1969. hdc = GetDC(NULL);
  1970. if (hdc == NULL)
  1971. return NULL;
  1972. hdcMem = CreateCompatibleDC(NULL);
  1973. if (hdcMem == NULL) {
  1974. ReleaseDC(NULL, hdc);
  1975. return NULL;
  1976. }
  1977. if (gwOptions & OPT_TITLE) {
  1978. if (ghfontMap)
  1979. hfontOld = SelectObject(hdcMem, ghfontMap);
  1980. GetTextExtentPoint32(hdcMem, gachCaption, STRLEN(gachCaption), &TempSize);
  1981. xExt = max(TempSize.cx + 4, ICON_MINX);
  1982. yExt = TempSize.cy;
  1983. if (yExt > TITLE_HEIGHT) // don't let text be higher than bar
  1984. yExt = TITLE_HEIGHT;
  1985. if (xExt > rc.right) {
  1986. rc.left = (xExt - rc.right) / 2;
  1987. rc.right += rc.left;
  1988. } else {
  1989. xOff = (rc.right - xExt) /2;
  1990. xExt = rc.right;
  1991. }
  1992. if (rc.bottom < ICON_MINY) {
  1993. yOff = ICON_MINY;
  1994. rc.top = (ICON_MINY - rc.bottom) / 2;
  1995. rc.bottom += rc.top;
  1996. }
  1997. xSize = xExt; ySize = yOff + TITLE_HEIGHT;
  1998. } else {
  1999. if (rc.right < ICON_MINX) {
  2000. rc.left = (ICON_MINX - rc.right) / 2;
  2001. rc.right += rc.left;
  2002. }
  2003. if (rc.bottom < ICON_MINY) {
  2004. rc.top = (ICON_MINY - rc.bottom) / 2;
  2005. rc.bottom += rc.top;
  2006. }
  2007. xSize = max(rc.right, ICON_MINX);
  2008. ySize = max(rc.bottom, ICON_MINY);
  2009. }
  2010. /* Big enough to hold text caption too, if necessary */
  2011. hbm = CreateCompatibleBitmap(hdc, xSize, ySize);
  2012. ReleaseDC(NULL, hdc);
  2013. if (hbm == NULL) {
  2014. DeleteDC(hdcMem);
  2015. return NULL;
  2016. }
  2017. hbmT = SelectObject(hdcMem, hbm);
  2018. hbrOld = SelectObject(hdcMem, hbrWindowColour);
  2019. PatBlt(hdcMem, 0,0, xSize, ySize, PATCOPY);
  2020. SelectObject(hdcMem, hbrOld);
  2021. if (gwOptions & OPT_TITLE) {
  2022. hbrOld = SelectObject(hdcMem, hbrButtonFace);
  2023. PatBlt(hdcMem, 0, rc.bottom, xExt, TITLE_HEIGHT, PATCOPY);
  2024. SetBkMode(hdcMem, TRANSPARENT);
  2025. SetTextColor(hdcMem, rgbButtonText);
  2026. /* Centre text vertically in title bar */
  2027. TextOut(hdcMem, xOff + 2, yOff + (TITLE_HEIGHT - yExt) / 2,
  2028. gachCaption, STRLEN(gachCaption));
  2029. if (hbrOld)
  2030. SelectObject(hdcMem, hbrOld);
  2031. if (ghfontMap)
  2032. SelectObject(hdcMem, hfontOld);
  2033. }
  2034. /* Use our ICON as the picture */
  2035. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW)) {
  2036. xIconOffset = rc.left + (rc.right-rc.left-ICON_MINX)/2;
  2037. xIconOffset = xIconOffset < 0 ? 0: xIconOffset;
  2038. DrawIcon(hdcMem, xIconOffset, rc.top,
  2039. GetIconForCurrentDevice(GI_LARGE, IDI_DDEFAULT));
  2040. /* Use a frame of our file */
  2041. } else {
  2042. LOADSTRING(IDS_NOPICTURE, ach);
  2043. DrawText(hdcMem, ach, STRLEN(ach), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  2044. mciUpdate.hDC = hdcMem;
  2045. mciUpdate.dwCallback = 0;
  2046. SetRectEmpty(&mciUpdate.rc);
  2047. /* NO matter what size our playback window is, we want to use the */
  2048. /* original size of the window as the picture we put on the clipbrd */
  2049. SetViewportOrgEx(hdcMem, rc.left, rc.top, NULL);
  2050. GetDestRectMCI(&rcSave);
  2051. SetDestRectMCI(&grcSize);
  2052. dw = mciSendCommand(gwDeviceID, MCI_UPDATE,
  2053. MCI_ANIM_UPDATE_HDC | MCI_WAIT, (DWORD_PTR)(LPVOID)&mciUpdate);
  2054. SetDestRectMCI(&rcSave);
  2055. SetViewportOrgEx(hdcMem, 0, 0, NULL);
  2056. }
  2057. if (gwOptions & OPT_BORDER) {
  2058. SetRect(&rc, 0, 0, xSize, ySize);
  2059. FrameRect(hdcMem, &rc, GetStockObject(BLACK_BRUSH));
  2060. if (gwOptions & OPT_TITLE) {
  2061. SetRect(&rc, 0, ySize - TITLE_HEIGHT, xSize, ySize-TITLE_HEIGHT+1);
  2062. FrameRect(hdcMem, &rc, GetStockObject(BLACK_BRUSH));
  2063. }
  2064. }
  2065. if (hbmT)
  2066. SelectObject(hdcMem, hbmT);
  2067. DeleteDC(hdcMem);
  2068. grcSize=rcs;
  2069. return hbm;
  2070. }
  2071. //
  2072. // if we are on a palette device, dither to the VGA colors
  2073. // for apps that dont deal with palettes!
  2074. //
  2075. void FAR PASCAL DitherMCI(HANDLE hdib, HPALETTE hpal)
  2076. {
  2077. LPBYTE lpBits;
  2078. int i;
  2079. LPBITMAPINFOHEADER lpbi;
  2080. DPF2("DitherMCI\n");
  2081. lpbi = (LPVOID)GLOBALLOCK(hdib);
  2082. if (lpbi == NULL)
  2083. return;
  2084. ////////////////////////////////////////////////////////////////////////
  2085. //
  2086. // HACK!!! patch the fake gamma-corrected colors to match the VGA's
  2087. //
  2088. ////////////////////////////////////////////////////////////////////////
  2089. lpBits = (LPBYTE)(lpbi+1);
  2090. for (i=0; i<8*4; i++)
  2091. {
  2092. if (lpBits[i] == 191)
  2093. lpBits[i] = 128;
  2094. }
  2095. ////////////////////////////////////////////////////////////////////////
  2096. lpBits = (LPBYTE)(lpbi+1) + 256 * sizeof(RGBQUAD);
  2097. BltProp(lpbi,lpBits,0,0,(int)lpbi->biWidth,(int)lpbi->biHeight,
  2098. lpbi,lpBits,0,0);
  2099. GLOBALUNLOCK(hdib);
  2100. }
  2101. void FAR PASCAL CopyMCI(HWND hwnd)
  2102. {
  2103. HBITMAP hbm;
  2104. HPALETTE hpal;
  2105. HANDLE hdib;
  2106. HANDLE hmfp;
  2107. HDC hdc;
  2108. DPF2("CopyMCI\n");
  2109. if (gwDeviceID == (UINT)0)
  2110. return;
  2111. if (hwnd) {
  2112. if (!OpenClipboard(ghwndApp))
  2113. return;
  2114. EmptyClipboard();
  2115. }
  2116. hpal = PaletteMCI();
  2117. hbm = BitmapMCI();
  2118. hdib = DibFromBitmap(hbm, hpal);
  2119. hpal = CopyPalette(hpal);
  2120. //
  2121. // if we are on a palette device. possibly dither to the VGA colors
  2122. // for apps that dont deal with palettes!
  2123. //
  2124. hdc = GetDC(NULL);
  2125. if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) &&
  2126. (gwOptions & OPT_DITHER) && (gwDeviceType & DTMCI_CANWINDOW)) {
  2127. DitherMCI(hdib, hpal);
  2128. hpal = NULL;
  2129. }
  2130. ReleaseDC(NULL, hdc);
  2131. hmfp = PictureFromDib(hdib, hpal);
  2132. if (hmfp)
  2133. SetClipboardData(CF_METAFILEPICT, hmfp);
  2134. if (hdib)
  2135. SetClipboardData(CF_DIB, hdib);
  2136. if (hpal)
  2137. SetClipboardData(CF_PALETTE, hpal);
  2138. //// we want people to pick the meta file always.
  2139. ////if (hbm)
  2140. //// SetClipboardData(CF_BITMAP, hbm);
  2141. if (hbm)
  2142. DeleteObject(hbm);
  2143. /* If not everything can be copied to the clipboard, error out and */
  2144. /* don't put anything up there. */
  2145. if (!hmfp || !hdib) {
  2146. EmptyClipboard();
  2147. Error(ghwndApp, IDS_CANTCOPY);
  2148. }
  2149. if (hwnd)
  2150. CloseClipboard();
  2151. }
  2152. /* MCIWndProc()
  2153. *
  2154. * Window procedure for MCI element window.
  2155. * This also initiates the the OLE2 drag-drop data transfer if required.
  2156. */
  2157. LONG_PTR FAR PASCAL _EXPORT
  2158. MCIWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  2159. {
  2160. PAINTSTRUCT ps; // information from BeginPaint()
  2161. HDC hdc;
  2162. DWORD dw; // function return status
  2163. MCI_ANIM_UPDATE_PARMS mciUpdate;
  2164. RECT rc;
  2165. static BOOL fDragCapture = FALSE;
  2166. static RECT rcWin;
  2167. POINT pt;
  2168. switch (msg)
  2169. {
  2170. // case WM_NCHITTEST:
  2171. // return HTTRANSPARENT;
  2172. case WM_CREATE:
  2173. ghwndMCI = hwnd;
  2174. SetWindowMCI(hwnd);
  2175. break;
  2176. case WM_SIZE:
  2177. GetClientRect(hwnd, &rc);
  2178. SetDestRectMCI(&rc);
  2179. break;
  2180. case WM_CLOSE:
  2181. SetWindowMCI(NULL);
  2182. break;
  2183. case WM_DESTROY:
  2184. SetWindowMCI(NULL);
  2185. ghwndMCI = NULL;
  2186. CleanUpDrag();
  2187. break;
  2188. case WM_RBUTTONDOWN:
  2189. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_STOP, 0);
  2190. break;
  2191. case WM_LBUTTONDOWN:
  2192. switch(gwStatus) {
  2193. case MCI_MODE_PAUSE:
  2194. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  2195. break;
  2196. case MCI_MODE_PLAY:
  2197. case MCI_MODE_SEEK:
  2198. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PAUSE, 0);
  2199. break;
  2200. default:
  2201. //Capture to initiate the drag drop operation.
  2202. if (!gfOle2IPEditing) {
  2203. fDragCapture = TRUE;
  2204. SetCapture(hwnd);
  2205. GetClientRect(hwnd, (LPRECT)&rcWin);
  2206. MapWindowPoints(hwnd, NULL, (LPPOINT)&rcWin, 2);
  2207. }
  2208. }
  2209. break;
  2210. case WM_LBUTTONDBLCLK:
  2211. SeekMCI(gdwMediaStart);
  2212. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  2213. break;
  2214. case WM_LBUTTONUP:
  2215. if (!fDragCapture)
  2216. break;
  2217. fDragCapture = FALSE;
  2218. ReleaseCapture();
  2219. break;
  2220. case WM_MOUSEMOVE:
  2221. //Initiate drag drop if outside the window.
  2222. if (!fDragCapture)
  2223. break;
  2224. LONG2POINT(lParam, pt);
  2225. MapWindowPoints(hwnd, NULL, &pt, 1);
  2226. if (!PtInRect((LPRECT)&rcWin, pt)) {
  2227. ReleaseCapture();
  2228. DoDrag();
  2229. fDragCapture = FALSE;
  2230. } else {
  2231. SetCursor(LoadCursor(ghInst,MAKEINTRESOURCE(IDC_DRAG)));
  2232. }
  2233. break;
  2234. case WM_PALETTECHANGED:
  2235. InvalidateRect(hwnd, NULL, TRUE);
  2236. break;
  2237. case WM_QUERYNEWPALETTE:
  2238. if (gwDeviceID && (gwDeviceType & DTMCI_CANWINDOW)) {
  2239. mciSendCommand(gwDeviceID, MCI_REALIZE,
  2240. MCI_ANIM_REALIZE_NORM, 0L);
  2241. }
  2242. break;
  2243. case WM_ERASEBKGND:
  2244. /* Don't erase the part we'll paint into cuz we'd flicker */
  2245. /* and flicker is bad. */
  2246. if (gwDeviceID && (gwDeviceType & DTMCI_CANWINDOW)) {
  2247. GetDestRectMCI(&rc);
  2248. SaveDC((HDC)wParam);
  2249. ExcludeClipRect((HDC)wParam, rc.left, rc.top, rc.right,
  2250. rc.bottom);
  2251. DefWindowProc(hwnd, msg, wParam, lParam);
  2252. RestoreDC((HDC)wParam, -1);
  2253. }
  2254. return 0;
  2255. case WM_PAINT:
  2256. hdc = BeginPaint(hwnd, &ps);
  2257. if (gwDeviceID)
  2258. {
  2259. GetClientRect(hwnd, &rc);
  2260. if (gwDeviceType & DTMCI_CANWINDOW) {
  2261. mciUpdate.hDC = hdc;
  2262. /*!!! should we send MCI_DGV_UPDATE_PAINT? to non dgv devices? */
  2263. dw = mciSendCommand(gwDeviceID, MCI_UPDATE,
  2264. MCI_ANIM_UPDATE_HDC | MCI_WAIT |
  2265. MCI_DGV_UPDATE_PAINT,
  2266. (DWORD_PTR)(LPVOID)&mciUpdate);
  2267. //
  2268. // if the update fails then erase
  2269. //
  2270. if (dw != 0)
  2271. DefWindowProc(hwnd, WM_ERASEBKGND, (WPARAM)hdc, 0);
  2272. }
  2273. }
  2274. EndPaint(hwnd, &ps);
  2275. return 0;
  2276. }
  2277. return DefWindowProc(hwnd, msg, wParam, lParam);
  2278. }
  2279. ////////////////////////////////////////////////////////////////////////////
  2280. ////////////////////////////////////////////////////////////////////////////
  2281. ////////////////////////////////////////////////////////////////////////////
  2282. ////////////////////////////////////////////////////////////////////////////
  2283. ////////////////////////////////////////////////////////////////////////////
  2284. HPALETTE CopyPalette(HPALETTE hpal)
  2285. {
  2286. PLOGPALETTE ppal;
  2287. int nNumEntries = 0; // MUST initialise. GetObject stores TWO bytes
  2288. int i;
  2289. if (!hpal)
  2290. return NULL;
  2291. GetObject(hpal,sizeof(int),&nNumEntries);
  2292. if (nNumEntries == 0)
  2293. return NULL;
  2294. ppal = AllocMem(sizeof(LOGPALETTE) + nNumEntries * sizeof(PALETTEENTRY));
  2295. if (!ppal)
  2296. return NULL;
  2297. ppal->palVersion = 0x300;
  2298. ppal->palNumEntries = (USHORT)nNumEntries;
  2299. GetPaletteEntries(hpal,0,nNumEntries,ppal->palPalEntry);
  2300. for (i=0; i<nNumEntries; i++)
  2301. ppal->palPalEntry[i].peFlags = 0;
  2302. hpal = CreatePalette(ppal);
  2303. FreeMem(ppal, sizeof(LOGPALETTE) + nNumEntries * sizeof(PALETTEENTRY));
  2304. return hpal;
  2305. }
  2306. #ifdef UNUSED
  2307. HANDLE PictureFromBitmap(HBITMAP hbm, HPALETTE hpal)
  2308. {
  2309. LPMETAFILEPICT pmfp;
  2310. HANDLE hmfp;
  2311. HANDLE hmf;
  2312. HANDLE hdc;
  2313. HDC hdcMem;
  2314. BITMAP bm;
  2315. HBITMAP hbmT;
  2316. if (!hbm)
  2317. return NULL;
  2318. GetObject(hbm, sizeof(bm), (LPVOID)&bm);
  2319. hdcMem = CreateCompatibleDC(NULL);
  2320. if (!hdcMem)
  2321. return NULL;
  2322. hbmT = SelectObject(hdcMem, hbm);
  2323. hdc = CreateMetaFile(NULL);
  2324. if (!hdc) {
  2325. DeleteDC(hdcMem);
  2326. return NULL;
  2327. }
  2328. SetWindowOrgEx (hdc, 0, 0, NULL);
  2329. SetWindowExtEx (hdc, bm.bmWidth, bm.bmHeight, NULL);
  2330. if (hpal)
  2331. {
  2332. SelectPalette(hdcMem,hpal,FALSE);
  2333. RealizePalette(hdcMem);
  2334. SelectPalette(hdc,hpal,FALSE);
  2335. RealizePalette(hdc);
  2336. }
  2337. SetStretchBltMode(hdc, COLORONCOLOR);
  2338. BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdcMem,0,0,SRCCOPY);
  2339. hmf = CloseMetaFile(hdc);
  2340. SelectObject(hdcMem, hbmT);
  2341. DeleteDC(hdcMem);
  2342. if (hmfp = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)))
  2343. {
  2344. pmfp = (LPMETAFILEPICT)GLOBALLOCK(hmfp);
  2345. hdc = GetDC(NULL);
  2346. #if 1
  2347. pmfp->mm = MM_ANISOTROPIC;
  2348. pmfp->hMF = hmf;
  2349. pmfp->xExt = MulDiv(bm.bmWidth ,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2350. pmfp->yExt = MulDiv(bm.bmHeight,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2351. #else
  2352. pmfp->mm = MM_TEXT;
  2353. pmfp->hMF = hmf;
  2354. pmfp->xExt = bm.bmWidth;
  2355. pmfp->yExt = bm.bmHeight;
  2356. #endif
  2357. ReleaseDC(NULL, hdc);
  2358. }
  2359. else
  2360. {
  2361. DeleteMetaFile(hmf);
  2362. }
  2363. return hmfp;
  2364. }
  2365. #endif /* UNUSED */
  2366. HANDLE FAR PASCAL PictureFromDib(HANDLE hdib, HPALETTE hpal)
  2367. {
  2368. LPMETAFILEPICT pmfp;
  2369. HANDLE hmfp;
  2370. HANDLE hmf;
  2371. HANDLE hdc;
  2372. LPBITMAPINFOHEADER lpbi;
  2373. if (!hdib)
  2374. return NULL;
  2375. lpbi = (LPVOID)GLOBALLOCK(hdib);
  2376. if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
  2377. lpbi->biClrUsed = 1 << lpbi->biBitCount;
  2378. hdc = CreateMetaFile(NULL);
  2379. if (!hdc)
  2380. return NULL;
  2381. SetWindowOrgEx(hdc, 0, 0, NULL);
  2382. SetWindowExtEx(hdc, (int)lpbi->biWidth, (int)lpbi->biHeight, NULL);
  2383. if (hpal)
  2384. {
  2385. SelectPalette(hdc,hpal,FALSE);
  2386. RealizePalette(hdc);
  2387. }
  2388. SetStretchBltMode(hdc, COLORONCOLOR);
  2389. StretchDIBits(hdc,
  2390. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2391. 0,0,(int)lpbi->biWidth, (int)lpbi->biHeight,
  2392. (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  2393. (LPBITMAPINFO)lpbi,
  2394. DIB_RGB_COLORS,
  2395. SRCCOPY);
  2396. if (hpal)
  2397. SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
  2398. hmf = CloseMetaFile(hdc);
  2399. hmfp = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT));
  2400. if (hmfp)
  2401. {
  2402. pmfp = (LPMETAFILEPICT)GLOBALLOCK(hmfp);
  2403. hdc = GetDC(NULL);
  2404. #if 1
  2405. pmfp->mm = MM_ANISOTROPIC;
  2406. pmfp->hMF = hmf;
  2407. pmfp->xExt = MulDiv((int)lpbi->biWidth ,2540,GetDeviceCaps(hdc, LOGPIXELSX));
  2408. pmfp->yExt = MulDiv((int)lpbi->biHeight,2540,GetDeviceCaps(hdc, LOGPIXELSY));
  2409. extWidth = pmfp->xExt;
  2410. extHeight = pmfp->yExt;
  2411. DPF1("PictureFromDib: Bitmap %d x %d; metafile %d x %d\n", lpbi->biWidth, lpbi->biHeight, extWidth, extHeight);
  2412. #else
  2413. pmfp->mm = MM_TEXT;
  2414. pmfp->hMF = hmf;
  2415. pmfp->xExt = (int)lpbi->biWidth;
  2416. pmfp->yExt = (int)lpbi->biHeight;
  2417. #endif
  2418. ReleaseDC(NULL, hdc);
  2419. }
  2420. else
  2421. {
  2422. DeleteMetaFile(hmf);
  2423. }
  2424. GLOBALUNLOCK(hdib);
  2425. GLOBALUNLOCK(hmfp);
  2426. return hmfp;
  2427. }
  2428. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  2429. /*
  2430. * DibFromBitmap()
  2431. *
  2432. * Will create a global memory block in DIB format that represents the DDB
  2433. * passed in
  2434. *
  2435. */
  2436. HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal)
  2437. {
  2438. BITMAP bm;
  2439. BITMAPINFOHEADER bi;
  2440. BITMAPINFOHEADER FAR *lpbi;
  2441. DWORD dw;
  2442. HANDLE hdib;
  2443. HDC hdc;
  2444. HPALETTE hpalT;
  2445. if (!hbm)
  2446. return NULL;
  2447. GetObject(hbm,sizeof(bm),&bm);
  2448. bi.biSize = sizeof(BITMAPINFOHEADER);
  2449. bi.biWidth = bm.bmWidth;
  2450. bi.biHeight = bm.bmHeight;
  2451. bi.biPlanes = 1;
  2452. bi.biBitCount = (bm.bmPlanes * bm.bmBitsPixel) > 8 ? 24 : 8;
  2453. bi.biCompression = BI_RGB;
  2454. bi.biSizeImage = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
  2455. bi.biXPelsPerMeter = 0;
  2456. bi.biYPelsPerMeter = 0;
  2457. bi.biClrUsed = bi.biBitCount == 8 ? 256 : 0;
  2458. bi.biClrImportant = 0;
  2459. dw = bi.biSize + bi.biClrUsed * sizeof(RGBQUAD) + bi.biSizeImage;
  2460. hdib = GlobalAlloc(GHND | GMEM_DDESHARE, dw);
  2461. if (!hdib)
  2462. return NULL;
  2463. lpbi = (LPBITMAPINFOHEADER)GLOBALLOCK(hdib);
  2464. *lpbi = bi;
  2465. hdc = CreateCompatibleDC(NULL);
  2466. if (hpal && hdc)
  2467. {
  2468. hpalT = SelectPalette(hdc,hpal,FALSE);
  2469. RealizePalette(hdc);
  2470. }
  2471. GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight,
  2472. (LPBYTE)lpbi + (int)lpbi->biSize + (int)lpbi->biClrUsed * sizeof(RGBQUAD),
  2473. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  2474. if (hpal)
  2475. SelectPalette(hdc,hpalT,FALSE);
  2476. if (hdc)
  2477. DeleteDC(hdc);
  2478. GLOBALUNLOCK(hdib);
  2479. return hdib;
  2480. }
  2481. /* CreateSystemPalette()
  2482. *
  2483. * Return a palette which represents the system (physical) palette.
  2484. * By selecting this palette into a screen DC and realizing the palette,
  2485. * the exact physical mapping will be restored
  2486. *
  2487. * one use for this is when "snapping" the screen as a bitmap
  2488. *
  2489. * On error (e.g. out of memory), NULL is returned.
  2490. */
  2491. HPALETTE FAR PASCAL CreateSystemPalette()
  2492. {
  2493. HDC hdc; // DC onto the screen
  2494. int iSizePalette; // size of entire palette
  2495. int iFixedPalette; // number of reserved colors
  2496. int i;
  2497. struct {
  2498. WORD palVersion;
  2499. WORD palNumEntries;
  2500. PALETTEENTRY palPalEntry[256];
  2501. } pal;
  2502. hdc = GetDC(NULL);
  2503. if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
  2504. {
  2505. ReleaseDC(NULL,hdc);
  2506. return NULL;
  2507. }
  2508. iSizePalette = GetDeviceCaps(hdc, SIZEPALETTE);
  2509. //
  2510. // determine the number of 'static' system colors that
  2511. // are currently reserved
  2512. //
  2513. if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC)
  2514. iFixedPalette = GetDeviceCaps(hdc, NUMCOLORS);
  2515. else
  2516. iFixedPalette = 2;
  2517. //
  2518. // create a logical palette containing the system colors;
  2519. // this palette has all entries except fixed (system) colors
  2520. // flagged as PC_NOCOLLAPSE
  2521. //
  2522. pal.palVersion = 0x300;
  2523. pal.palNumEntries = (USHORT)iSizePalette;
  2524. GetSystemPaletteEntries(hdc, 0, iSizePalette, pal.palPalEntry);
  2525. ReleaseDC(NULL,hdc);
  2526. for (i = iFixedPalette/2; i < iSizePalette-iFixedPalette/2; i++)
  2527. pal.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
  2528. return CreatePalette((LPLOGPALETTE)&pal);
  2529. }