Leaked source code of windows server 2003
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.

1976 lines
60 KiB

  1. /*-----------------------------------------------------------------------------+
  2. | INIT.C |
  3. | |
  4. | This file houses the discardable code used at initialisation time. Among |
  5. | other things, this code reads .INI information and looks for MCI devices. |
  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. /* include files */
  14. #include <windows.h>
  15. #include <mmsystem.h>
  16. #include <mmddk.h>
  17. #include <stdlib.h>
  18. #include <shellapi.h>
  19. #include "mpole.h"
  20. #include "mplayer.h"
  21. #include "toolbar.h"
  22. #include "registry.h"
  23. DWORD gfdwFlagsEx;
  24. static SZCODE aszMPlayer[] = TEXT("MPlayer");
  25. extern char szToolBarClass[]; // toolbar class
  26. /*
  27. * Static variables
  28. *
  29. */
  30. HANDLE ghInstPrev;
  31. TCHAR gachAppName[40]; /* string holding the name of the app. */
  32. TCHAR gachClassRoot[48]; /* string holding the name of the app. */
  33. TCHAR aszNotReadyFormat[48];
  34. TCHAR aszReadyFormat[48];
  35. TCHAR aszDeviceMenuSimpleFormat[48];
  36. TCHAR aszDeviceMenuCompoundFormat[48];
  37. TCHAR gachOpenExtension[5] = TEXT("");/* Non-null if a device extension passed in */
  38. TCHAR gachOpenDevice[128] = TEXT(""); /* Non-null if a device extension passed in */
  39. TCHAR gachProgID[128] = TEXT("");
  40. CLSID gClsID;
  41. CLSID gClsIDOLE1Compat; /* For writing to IPersist - may be MPlayer's */
  42. /* OLE1 class ID or same as gClsID. */
  43. TCHAR gszMPlayerIni[40]; /* name of private .INI file */
  44. TCHAR gszHelpFileName[_MAX_PATH]; /* name of the help file */
  45. TCHAR gszHtmlHelpFileName[_MAX_PATH]; /* name of the html help file */
  46. PTSTR gpchFilter; /* GetOpenFileName() filter */
  47. PTSTR gpchInitialDir; /* GetOpenFileName() initial directory */
  48. RECT grcSave; /* size of mplayer before shrunk to */
  49. /* play only size. */
  50. int giDefWidth;
  51. extern BOOL gfSeenPBCloseMsg; //TRUE if the subclasses PlayBack WIndow Proc
  52. //has seen the WM_CLOSE message
  53. ////////////////////////////////////////////
  54. // these strings *must* be in DGROUP!
  55. static TCHAR aszNULL[] = TEXT("");
  56. static TCHAR aszAllFiles[] = TEXT("*.*");
  57. ////////////////////////////////////////////
  58. // strings for registration database - also referenced from fixreg.c
  59. SZCODE aszKeyMID[] = TEXT(".mid");
  60. SZCODE aszKeyRMI[] = TEXT(".rmi");
  61. SZCODE aszKeyAVI[] = TEXT(".avi");
  62. SZCODE aszKeyMMM[] = TEXT(".mmm");
  63. SZCODE aszKeyWAV[] = TEXT(".wav");
  64. static SZCODE aszFormatExts[] = TEXT("%s;*.%s");
  65. static SZCODE aszFormatExt[] = TEXT("*.%s");
  66. static SZCODE aszFormatFilter[] = TEXT("%s (%s)");
  67. static SZCODE aszPositionFormat[]= TEXT("%d,%d,%d,%d");
  68. static SZCODE aszSysIniTime[] = TEXT("SysIni");
  69. static SZCODE aszDisplayPosition[] = TEXT("DisplayPosition");
  70. SZCODE aszOptionsSection[] = TEXT("Options");
  71. static SZCODE aszShowPreview[] = TEXT("ShowPreview");
  72. static SZCODE aszWinIni[] = TEXT("win.ini");
  73. SZCODE aszIntl[] = TEXT("intl");
  74. TCHAR chDecimal = TEXT('.'); /* localised in AppInit, GetIntlSpecs */
  75. TCHAR chTime = TEXT(':'); /* localised in AppInit, GetIntlSpecs */
  76. TCHAR chLzero = TEXT('1');
  77. static SZCODE gszWinIniSection[] = TEXT("MCI Extensions"); /* section name in WIN.INI*/
  78. static SZCODE aszSystemIni[] = TEXT("SYSTEM.INI");
  79. #ifdef CHICAGO_PRODUCT
  80. static SZCODE gszSystemIniSection[] = TEXT("MCI");
  81. #else
  82. static SZCODE gszSystemIniSection[] = MCI_SECTION;
  83. #endif
  84. static SZCODE aszBlank[] = TEXT(" ");
  85. static SZCODE aszDecimalFormat[] = TEXT("%d");
  86. static SZCODE aszTrackClass[] = TEXT("MPlayerTrackMap");
  87. extern HMENU ghMenu; /* handle to main menu */
  88. extern HMENU ghDeviceMenu; /* handle to the Device menu */
  89. extern UINT gwCurScale; /* current scale style */
  90. extern HANDLE hAccel;
  91. extern int gcAccelEntries;
  92. /* private function prototypes */
  93. void NEAR PASCAL QueryDevices(void);
  94. void NEAR PASCAL BuildDeviceMenu(void);
  95. void NEAR PASCAL ReadDefaults(void);
  96. void NEAR PASCAL BuildFilter(void);
  97. BOOL PostOpenDialogMessage(void);
  98. extern BOOL InitServer(HWND, HANDLE);
  99. extern BOOL InitInstance (HANDLE);
  100. /**************************************************************************
  101. ScanCmdLine checks first for the following options
  102. -----------
  103. Open
  104. Play Only
  105. Close After Playing
  106. Embedded (play as a server)
  107. If the embedded flag is set, then the play only is also set.
  108. It then removes these options from the cmd line
  109. If no filename is present then turn close option off, and set the play
  110. option to have the same value as the embedded option
  111. If /WAVE, /MIDI or /VFW is specified along with /file,
  112. the file extension must match, otherwise the app exits.
  113. MPLAYER command options.
  114. MPLAYER [/open] [/play] [/close] [/embedding] [/WAV] [/MID] [/AVI] [file]
  115. /open open file if specified, otherwise put up dialog.
  116. /play play file right away.
  117. /close close after playing. (only valid with /play)
  118. /embedding run as an OLE server.
  119. /WAV open a wave file \
  120. /MID open a midi file > Valid with /open
  121. /AVI open an AVI file /
  122. [file] file or device to open.
  123. ***************************************************************************/
  124. static SZCODE aszEmbedding[] = TEXT("Embedding");
  125. static SZCODE aszPlayOnly[] = TEXT("Play");
  126. static SZCODE aszClose[] = TEXT("Close");
  127. static SZCODE aszOpen[] = TEXT("Open");
  128. static SZCODE aszWAVE[] = TEXT("WAVE");
  129. static SZCODE aszMIDI[] = TEXT("MIDI");
  130. static SZCODE aszVFW[] = TEXT("VFW");
  131. BOOL NEAR PASCAL ScanCmdLine(LPTSTR szCmdLine)
  132. {
  133. int i;
  134. TCHAR buf[100];
  135. LPTSTR sz=szCmdLine;
  136. gfPlayOnly = FALSE;
  137. gfCloseAfterPlaying = FALSE;
  138. gfRunWithEmbeddingFlag = FALSE;
  139. while (*sz == TEXT(' '))
  140. sz++;
  141. while (*sz == TEXT('-') || *sz == TEXT('/')) {
  142. for (i=0,sz++; *sz && *sz != TEXT(' ') && (i < 99); buf[i++] = *sz++)
  143. ;
  144. buf[i++] = 0;
  145. if (!lstrcmpi(buf, aszPlayOnly)) {
  146. gfPlayOnly = TRUE;
  147. }
  148. if (!lstrcmpi(buf, aszOpen))
  149. gfOpenDialog = TRUE;
  150. /* Check for open option, but accept only the first: */
  151. if (!gachOpenDevice[0]
  152. && (GetProfileString(gszWinIniSection, buf, aszNULL, gachOpenDevice,
  153. CHAR_COUNT(gachOpenDevice)) > 0))
  154. {
  155. /* Take a copy of the extension, which we will use to find stuff
  156. * in the registry relating to OLE:
  157. */
  158. gachOpenExtension[0] = TEXT('.');
  159. lstrcpy(&gachOpenExtension[1], buf);
  160. }
  161. if (!lstrcmpi(buf, aszClose))
  162. gfCloseAfterPlaying = TRUE;
  163. if (!lstrcmpi(buf, aszEmbedding))
  164. gfRunWithEmbeddingFlag = TRUE;
  165. if (gfRunWithEmbeddingFlag) {
  166. gfPlayOnly = TRUE;
  167. }
  168. while (*sz == TEXT(' '))
  169. sz++;
  170. }
  171. /*
  172. ** Do we have a long file name with spaces in it ?
  173. ** This is most likely to have come from the FileMangler.
  174. ** If so copy the file name without the quotes.
  175. */
  176. if ( *sz == TEXT('\'') || *sz == TEXT('\"') ) {
  177. TCHAR ch = *sz; // Remember which quote character it was
  178. // According to the DOCS " is invalid in a filename...
  179. i = 0;
  180. /* Move over the initial quote, then copy the filename */
  181. while ( *++sz && *sz != ch ) {
  182. szCmdLine[i++] = *sz;
  183. }
  184. szCmdLine[i] = TEXT('\0');
  185. }
  186. else {
  187. lstrcpy( szCmdLine, sz ); // remove options
  188. }
  189. // It's assumed that OLE2 servers don't accept file name
  190. // with -Embedding.
  191. // (Not doing this caused Win95 bug 4096 with OLE1 apps,
  192. // because MPlayer loaded the file, and, in the meantime,
  193. // OLE called PFLoad, resulting in OpenMCI being called
  194. // recursively.)
  195. if (gfRunWithEmbeddingFlag)
  196. szCmdLine[0] = TEXT('\0');
  197. //
  198. // if there's /play, make sure there's /open
  199. // (this may affect the checks below)
  200. //
  201. if (gfPlayOnly && !gfRunWithEmbeddingFlag)
  202. gfOpenDialog = TRUE;
  203. //
  204. // if no file specifed ignore the /play option
  205. //
  206. if (szCmdLine[0] == 0 && !gfOpenDialog) {
  207. gfPlayOnly = gfRunWithEmbeddingFlag;
  208. }
  209. //
  210. // if file specifed ignore the /open option
  211. //
  212. if (szCmdLine[0] != 0) {
  213. gfOpenDialog = FALSE;
  214. }
  215. if (!gfPlayOnly && szCmdLine[0] == 0)
  216. gfCloseAfterPlaying = FALSE;
  217. SetEvent(heventCmdLineScanned);
  218. return gfRunWithEmbeddingFlag;
  219. }
  220. BOOL ResolveIfLink(PTCHAR szFileName);
  221. BOOL ProgIDFromExtension(LPTSTR szExtension, LPTSTR szProgID, DWORD BufSize /* in BYTES */)
  222. {
  223. DWORD Status;
  224. HKEY hkeyExtension;
  225. BOOL rc = FALSE;
  226. DWORD Type;
  227. DWORD Size;
  228. Status = RegOpenKeyEx( HKEY_CLASSES_ROOT, szExtension, 0,
  229. KEY_READ, &hkeyExtension );
  230. if (Status == NO_ERROR)
  231. {
  232. Size = BufSize;
  233. Status = RegQueryValueEx( hkeyExtension,
  234. aszNULL,
  235. 0,
  236. &Type,
  237. (LPBYTE)szProgID,
  238. &Size );
  239. if (Status == NO_ERROR)
  240. {
  241. rc = TRUE;
  242. }
  243. else
  244. {
  245. DPF0("Couldn't find ProgID for extension %"DTS"\n", szExtension);
  246. }
  247. RegCloseKey(hkeyExtension);
  248. }
  249. return rc;
  250. }
  251. BOOL GetClassNameFromProgID(LPTSTR szProgID, LPTSTR szClassName, DWORD BufSize /* in BYTES */)
  252. {
  253. DWORD Status;
  254. HKEY hkeyProgID;
  255. BOOL rc = FALSE;
  256. DWORD Type;
  257. DWORD Size;
  258. Status = RegOpenKeyEx( HKEY_CLASSES_ROOT, szProgID, 0,
  259. KEY_READ, &hkeyProgID );
  260. if (Status == NO_ERROR)
  261. {
  262. Size = BufSize;
  263. Status = RegQueryValueEx( hkeyProgID,
  264. aszNULL,
  265. 0,
  266. &Type,
  267. (LPBYTE)szClassName,
  268. &Size );
  269. if (Status == NO_ERROR)
  270. {
  271. DPF1("Found Class Name %"DTS" for ProgID %"DTS"\n", szClassName, szProgID);
  272. rc = TRUE;
  273. }
  274. else
  275. {
  276. DPF0("Couldn't find Class Name for ProgID %"DTS"\n", szProgID);
  277. }
  278. RegCloseKey(hkeyProgID);
  279. }
  280. return rc;
  281. }
  282. /**************************************************************************
  283. ***************************************************************************/
  284. BOOL FAR PASCAL ProcessCmdLine(HWND hwnd, LPTSTR szCmdLine)
  285. {
  286. BOOL f;
  287. LPTSTR lp;
  288. SCODE status;
  289. CLSID ClsID;
  290. LPWSTR pUnicodeProgID;
  291. if (gfRunWithEmbeddingFlag)
  292. {
  293. srvrMain.cRef++;
  294. gClsID = CLSID_MPLAYER;
  295. gClsIDOLE1Compat = CLSID_OLE1MPLAYER;
  296. if (*gachOpenExtension)
  297. {
  298. /* We accept as a parameter the extension of a registered type.
  299. * If we can find a corresponding Prog ID in the registry and
  300. * a class ID, we register ourselves with that class ID:
  301. */
  302. if(ProgIDFromExtension(gachOpenExtension, gachProgID, CHAR_COUNT(gachProgID)))
  303. {
  304. #ifndef UNICODE
  305. pUnicodeProgID = AllocateUnicodeString(gachProgID);
  306. #else
  307. pUnicodeProgID = gachProgID;
  308. #endif
  309. if (CLSIDFromProgID(pUnicodeProgID, &ClsID) == S_OK)
  310. {
  311. /* No OLE1 compatibility for this class:
  312. */
  313. gClsID = gClsIDOLE1Compat = ClsID;
  314. }
  315. else
  316. {
  317. DPF0("Couldn't get CLSID for %"DTS"\n", gachProgID);
  318. }
  319. #ifndef UNICODE
  320. FreeUnicodeString(pUnicodeProgID);
  321. #endif
  322. }
  323. }
  324. if (*gachProgID)
  325. GetClassNameFromProgID(gachProgID, gachClassRoot, CHAR_COUNT(gachClassRoot));
  326. else
  327. LOADSTRING(IDS_CLASSROOT, gachClassRoot);
  328. status = GetScode(CoRegisterClassObject(&gClsID, (IUnknown FAR *)&srvrMain,
  329. CLSCTX_LOCAL_SERVER,
  330. REGCLS_SINGLEUSE, &srvrMain.dwRegCF));
  331. DPF("CoRegisterClassObject\n");
  332. srvrMain.cRef--;
  333. if (status != S_OK)
  334. {
  335. DPF0("CoRegisterClassObject failed with error %08x\n", status);
  336. return FALSE;
  337. }
  338. }
  339. else
  340. InitNewDocObj(&docMain);
  341. if (gfRunWithEmbeddingFlag)
  342. SetEmbeddedObjectFlag(TRUE);
  343. if (*szCmdLine != 0)
  344. {
  345. HCURSOR hcurPrev;
  346. InitDeviceMenu();
  347. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  348. WaitForDeviceMenu();
  349. SetCursor(hcurPrev);
  350. ResolveIfLink(szCmdLine);
  351. /* Change trailing white space to \0 because mci barfs on filenames */
  352. /* with trailing whitespace. */
  353. for (lp = szCmdLine; *lp; lp++);
  354. for (lp--; *lp == TEXT(' ') || *lp == TEXT('\t'); *lp = TEXT('\0'), lp--);
  355. f = OpenMciDevice(szCmdLine, NULL);
  356. if (f)
  357. CreateDocObjFromFile(szCmdLine, &docMain);
  358. if (gfRunWithEmbeddingFlag && !f) {
  359. DPF0("Error opening link, quiting...");
  360. PostMessage(ghwndApp, WM_CLOSE, 0, 0);
  361. }
  362. SetMPlayerIcon();
  363. return f;
  364. }
  365. return TRUE;
  366. }
  367. /**************************************************************************
  368. ***************************************************************************/
  369. /* At time of writing, this stuff isn't in Daytona;
  370. */
  371. #ifndef WS_EX_LEFTSCROLLBAR
  372. #define WS_EX_LEFTSCROLLBAR 0
  373. #define WS_EX_RIGHT 0
  374. #define WS_EX_RTLREADING 0
  375. #endif
  376. BOOL FAR PASCAL AppInit(HANDLE hInst, HANDLE hPrev, LPTSTR szCmdLine)
  377. {
  378. WNDCLASS cls; /* window class structure used for initialization */
  379. TCHAR ach[80];
  380. HCURSOR hcurPrev; /* the pre-hourglass cursor */
  381. /* Get the debug level from the WIN.INI [Debug] section. */
  382. #ifdef DEBUG
  383. if(__iDebugLevel == 0) // So we can set it in the debugger
  384. __iDebugLevel = GetProfileIntA("Debug", "MPlayer", 0);
  385. DPF("debug level %d\n", __iDebugLevel);
  386. #endif
  387. DPF("AppInit: cmdline = '%"DTS"'\n", (LPTSTR)szCmdLine);
  388. /* Save the instance handle in a global variable for later use. */
  389. ghInst = hInst;
  390. /* Retrieve the RTL state of the binary */
  391. LOADSTRING(IDS_IS_RTL, ach);
  392. gfdwFlagsEx = (ach[0] == TEXT('1')) ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0;
  393. LOADSTRING(IDS_MPLAYERWIDTH, ach);
  394. giDefWidth = ATOI(ach);
  395. if (giDefWidth <= 0) //bogus
  396. giDefWidth = DEF_WIDTH;
  397. /* Retrieve the name of the application and store it in <gachAppName>. */
  398. if (!LOADSTRING(IDS_APPNAME, gachAppName))
  399. return Error(ghwndApp, IDS_OUTOFMEMORY);
  400. LOADSTRING(IDS_DEVICEMENUCOMPOUNDFORMAT, aszDeviceMenuCompoundFormat);
  401. LOADSTRING(IDS_DEVICEMENUSIMPLEFORMAT, aszDeviceMenuSimpleFormat);
  402. LOADSTRING(IDS_NOTREADYFORMAT, aszNotReadyFormat);
  403. LOADSTRING(IDS_READYFORMAT, aszReadyFormat);
  404. LoadStatusStrings();
  405. //
  406. // read needed things from the [Intl] section of WIN.INI
  407. //
  408. GetIntlSpecs();
  409. /* Enable / disable the buttons, and display everything */
  410. /* unless we were run as an OLE server....*/
  411. ScanCmdLine(szCmdLine);
  412. gszCmdLine = szCmdLine;
  413. //Truncate if string is longer than MAX_PATH after ScanCmdLine()
  414. // due to the inability to handle longer strings in following modules
  415. if (STRLEN(gszCmdLine) >= MAX_PATH)
  416. {
  417. gszCmdLine[MAX_PATH - 1] = TEXT('\0');
  418. }
  419. if (!toolbarInit() ||
  420. !InitMCI(hPrev, hInst) ||
  421. !ControlInit (hInst)) {
  422. Error(NULL, IDS_OUTOFMEMORY);
  423. return FALSE;
  424. }
  425. if (!(hAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(MPLAYERACCEL)))) {
  426. Error(NULL, IDS_OUTOFMEMORY);
  427. return FALSE;
  428. }
  429. /* This rather obscure call is to get the number of entries
  430. * in the accelerator table to pass to IsAccelerator.
  431. * It isn't entirely obvious why IsAccelerator needs to be
  432. * told how many entries there are.
  433. */
  434. if (gfRunWithEmbeddingFlag)
  435. gcAccelEntries = CopyAcceleratorTable(hAccel, NULL, 0);
  436. /* Make the dialog box's icon identical to the MPlayer icon */
  437. hiconApp = LoadIcon(ghInst, MAKEINTRESOURCE(APPICON));
  438. if (!hPrev) {
  439. cls.lpszClassName = aszTrackClass;
  440. cls.lpfnWndProc = fnMPlayerTrackMap;
  441. cls.style = CS_VREDRAW;
  442. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  443. cls.hIcon = NULL;
  444. cls.lpszMenuName = NULL;
  445. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  446. cls.hInstance = ghInst;
  447. cls.cbClsExtra = 0;
  448. cls.cbWndExtra = 0;
  449. RegisterClass(&cls);
  450. /*
  451. * Initialize and register the "MPlayer" class.
  452. *
  453. */
  454. cls.lpszClassName = aszMPlayer;
  455. cls.lpfnWndProc = MPlayerWndProc;
  456. cls.style = CS_VREDRAW;
  457. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  458. cls.hIcon = hiconApp;
  459. cls.lpszMenuName = NULL;
  460. cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  461. cls.hInstance = ghInst;
  462. cls.cbClsExtra = 0;
  463. cls.cbWndExtra = DLGWINDOWEXTRA;
  464. RegisterClass(&cls);
  465. }
  466. // set ghInstPrev to the handle of the first mplayer instance by
  467. // FindWindow (hPrev will always be NULL). This global is checked
  468. // by window positioning code to behave differently for the second
  469. // and subsequent instances - so make sure it is NULL in the first case
  470. // and non-null in the others.
  471. // note we can't check for the window title, only the class, since
  472. // in play-only mode, the window title is *just* the name of the file.
  473. ghInstPrev = FindWindow(aszMPlayer, NULL);
  474. /*
  475. * Retain a pointer to the command line parameter string so that the player
  476. * can automatically open a file or device if one was specified on the
  477. * command line.
  478. *
  479. */
  480. if(!InitInstance (hInst))
  481. return FALSE;
  482. gwHeightAdjust = 2 * GetSystemMetrics(SM_CYFRAME) +
  483. GetSystemMetrics(SM_CYCAPTION) +
  484. GetSystemMetrics(SM_CYBORDER) +
  485. GetSystemMetrics(SM_CYMENU);
  486. /* create the main (control) window */
  487. ghwndApp = CreateWindowEx(gfdwFlagsEx,
  488. aszMPlayer,
  489. gachAppName,
  490. WS_THICKFRAME | WS_OVERLAPPED | WS_CAPTION |
  491. WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX,
  492. CW_USEDEFAULT,
  493. 0,
  494. giDefWidth,
  495. MAX_NORMAL_HEIGHT + gwHeightAdjust,
  496. NULL, // no parent
  497. NULL, // use class menu
  498. hInst, // instance
  499. NULL); // no data
  500. if (!ghwndApp) {
  501. DPF0("CreateWindowEx failed for main window: Error %d\n", GetLastError());
  502. return FALSE;
  503. }
  504. DPF("\n**********After create set\n");
  505. /****
  506. Removed from WM_CREATE so that it can be called similar to the way sdemo1
  507. i.e. after the create window call has completed
  508. May be completely unnecessary
  509. *****/
  510. /* Process dragged and dropped file */
  511. DragAcceptFiles(ghwndApp, TRUE);
  512. /* We will check that this has been filled in before calling
  513. * CoDisconnectObject. It should be non-null if an instance of the OLE
  514. * server has been created.
  515. */
  516. docMain.hwnd = NULL;
  517. /* Initialize the OLE server if appropriate.
  518. * If we don't initialize OLE here, a Copy will cause it to be initialized:
  519. */
  520. if (gfRunWithEmbeddingFlag)
  521. {
  522. if (InitOLE(&gfOleInitialized, &lpMalloc))
  523. InitServer(ghwndApp, ghInst);
  524. else
  525. return FALSE;
  526. }
  527. if (!gfRunWithEmbeddingFlag && (!gfPlayOnly || gszCmdLine[0]==0) && !gfOpenDialog)
  528. {
  529. ShowWindow(ghwndApp,giCmdShow);
  530. if (giCmdShow != SW_SHOWNORMAL)
  531. Layout();
  532. UpdateDisplay();
  533. UpdateWindow(ghwndApp);
  534. }
  535. /* Show the 'Wait' cursor in case this takes a long time */
  536. hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
  537. /*
  538. * Read the SYSTEM.INI and MPLAYER.INI files to see what devices
  539. * are available.
  540. */
  541. if (gfPlayOnly)
  542. garMciDevices[0].wDeviceType = DTMCI_CANPLAY | DTMCI_FILEDEV;
  543. //
  544. // this may open a file....
  545. //
  546. if (!ProcessCmdLine(ghwndApp,gszCmdLine)) {
  547. DPF0("ProcessCmdLine failed\n");
  548. return FALSE;
  549. }
  550. /* Restore the original cursor */
  551. if (hcurPrev)
  552. SetCursor(hcurPrev);
  553. /* Check for options to put up initial dialog etc.:
  554. */
  555. if (gfOpenDialog)
  556. {
  557. if (!PostOpenDialogMessage())
  558. {
  559. PostMessage(ghwndApp, WM_CLOSE, 0, 0);
  560. return FALSE;
  561. }
  562. }
  563. /* The "Play" button should have the focus initially */
  564. if (!gfRunWithEmbeddingFlag && !gfOpenDialog)
  565. {
  566. //SetFocus(ghwndToolbar); //setting focus messes up the menu access
  567. //using the ALT key
  568. // HACK!!! Want play button
  569. if (gfPlayOnly) {
  570. if (gwDeviceID == (UINT)0 || !(gwDeviceType & DTMCI_CANWINDOW)) {
  571. gfPlayOnly = FALSE;
  572. SizeMPlayer();
  573. }
  574. ShowWindow(ghwndApp,giCmdShow);
  575. if (giCmdShow != SW_SHOWNORMAL)
  576. Layout();
  577. /* stop any system sound from playing so the MCI device
  578. can have it HACK!!!! */
  579. sndPlaySound(NULL, 0);
  580. if (gwDeviceID)
  581. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  582. }
  583. }
  584. return TRUE;
  585. }
  586. /* PostOpenDialogMessage
  587. *
  588. * This routine is called if /open was in the command line.
  589. * If there was also an open option (/MIDI, /VFW or /WAVE in the command line,
  590. * it causes an Open dialog to be displayed, as would appear via the Device menu.
  591. * Otherwise it simulates File.Open.
  592. *
  593. * When this is called, the main window is hidden. The window must be made
  594. * visible when the dialog is dismissed. Calling CompleteOpenDialog(TRUE)
  595. * will achieve this.
  596. *
  597. * Returns TRUE if a message was posted, otherwise FALSE.
  598. *
  599. *
  600. * Global variables referenced:
  601. *
  602. * gachOpenExtension
  603. * ghwndApp
  604. *
  605. *
  606. * Andrew Bell, 1 July 1994
  607. *
  608. */
  609. BOOL PostOpenDialogMessage( )
  610. {
  611. BOOL Result = TRUE;
  612. InitDeviceMenu();
  613. WaitForDeviceMenu();
  614. if (*gachOpenExtension)
  615. {
  616. if (gwNumDevices)
  617. {
  618. /* If we've got here, the user specified a device, and that's
  619. * the only one the Device menu lists, so go ahead and open it:
  620. */
  621. PostMessage(ghwndApp, WM_COMMAND, IDM_DEVICE0 + 1, 0);
  622. }
  623. else
  624. {
  625. /* Couldn't find a device. Put up an error message then close
  626. * MPlayer down:
  627. */
  628. SendMessage(ghwndApp, WM_NOMCIDEVICES, 0, 0);
  629. Result = FALSE;
  630. }
  631. }
  632. else
  633. {
  634. /* No option specified, so put up the generic open dialog:
  635. */
  636. PostMessage(ghwndApp, WM_COMMAND, IDM_OPEN, 0);
  637. }
  638. return Result;
  639. }
  640. /* CompleteOpenDialog
  641. *
  642. * This should be called after the initial Open dialog (i.e. if gfOpenDialog
  643. * is TRUE). It makes MPlayer visible if a file was selected, otherwise posts
  644. * a close message to the app.
  645. *
  646. *
  647. * Global variables referenced:
  648. *
  649. * ghwndApp
  650. * gfOpenDialog
  651. * gfPlayOnly
  652. *
  653. *
  654. * Andrew Bell, 1 July 1994
  655. */
  656. VOID FAR PASCAL CompleteOpenDialog(BOOL FileSelected)
  657. {
  658. if (FileSelected)
  659. {
  660. /* We were invoked with /open, and came up invisible.
  661. * Now make ourselves visible:
  662. */
  663. gfOpenDialog = FALSE; // Used on init only
  664. ShowWindow(ghwndApp, SW_SHOWNORMAL);
  665. if (gfPlayOnly)
  666. PostMessage(ghwndApp, WM_COMMAND, (WPARAM)ID_PLAY, 0);
  667. }
  668. else
  669. {
  670. /* We were invoked with /open, and user cancelled
  671. * out of the open dialog.
  672. */
  673. PostMessage(ghwndApp, WM_CLOSE, 0, 0);
  674. }
  675. }
  676. void SubClassTrackbarWindow();
  677. void CreateControls()
  678. {
  679. int i;
  680. #define APP_NUMTOOLS 7
  681. static int aiButton[] = { BTN_PLAY, BTN_STOP,BTN_EJECT,
  682. BTN_HOME, BTN_RWD, BTN_FWD,BTN_END};
  683. /*
  684. * CREATE THE CONTROLS NEEDED FOR THE CONTROL PANEL DISPLAY
  685. * in the proper order so tabbing z-order works logically
  686. */
  687. /******* Make the Track bar ********/
  688. if (!ghwndTrackbar)
  689. ghwndTrackbar = CreateWindowEx(gfdwFlagsEx,
  690. TRACKBAR_CLASS,
  691. NULL,
  692. TBS_ENABLESELRANGE |
  693. (gfPlayOnly ? TBS_BOTH | TBS_NOTICKS : 0 ) |
  694. WS_CLIPSIBLINGS | WS_CHILD | WS_VISIBLE | WS_TABSTOP,
  695. 0,
  696. 0,
  697. 0,
  698. 0,
  699. ghwndApp,
  700. NULL,
  701. ghInst,
  702. NULL);
  703. SubClassTrackbarWindow();
  704. /******* Make the TransportButtons Toolbar ********/
  705. if (!ghwndToolbar) {
  706. ghwndToolbar = toolbarCreateMain(ghwndApp);
  707. #if 0 //VIJR-TB
  708. CreateWindowEx(gfdwFlagsEx,
  709. szToolBarClass,
  710. NULL,
  711. WS_CHILD | WS_VISIBLE | WS_TABSTOP |
  712. WS_CLIPSIBLINGS,
  713. 0,
  714. 0,
  715. 0,
  716. 0,
  717. ghwndApp,
  718. NULL,
  719. ghInst,
  720. NULL);
  721. #endif
  722. /* set the bitmap and button size to be used for this toolbar */
  723. #if 0 //VIJR-TB
  724. pt.x = BUTTONWIDTH;
  725. pt.y = BUTTONHEIGHT;
  726. toolbarSetBitmap(ghwndToolbar, ghInst, IDBMP_TOOLBAR, pt);
  727. #endif
  728. for (i = 0; i < 2; i++) {
  729. toolbarAddTool(ghwndToolbar, aiButton[i], TBINDEX_MAIN, BTNST_UP);
  730. }
  731. }
  732. /* Create a font for use in the track map and embedded object captions. */
  733. if (ghfontMap == NULL) {
  734. LOGFONT lf;
  735. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (LPVOID)&lf,
  736. 0);
  737. ghfontMap = CreateFontIndirect(&lf);
  738. }
  739. /******* we have been here before *******/
  740. if (ghwndFSArrows)
  741. return;
  742. /******* add more buttons to the toolbar ******/
  743. for (i = 2; i < APP_NUMTOOLS; i++) {
  744. if (i==3)
  745. toolbarAddTool(ghwndToolbar, BTN_SEP, TBINDEX_MAIN, 0);
  746. toolbarAddTool(ghwndToolbar, aiButton[i], TBINDEX_MAIN, BTNST_UP);
  747. }
  748. /******* load menus ********/
  749. /* Set up the menu system for this dialog */
  750. if (ghMenu == NULL)
  751. ghMenu = LoadMenu(ghInst, aszMPlayer);
  752. ghDeviceMenu = GetSubMenu(ghMenu, 2);
  753. /******* Make the Arrows for the Scrollbar Toolbar ********/
  754. // No tabstop, because arrows would steal focus from thumb
  755. ghwndFSArrows = toolbarCreateArrows(ghwndApp);
  756. #if 0 //VIJR-TB
  757. CreateWindowEx(gfdwFlagsEx,
  758. szToolBarClass,
  759. NULL,
  760. WS_CLIPSIBLINGS | WS_CHILD|WS_VISIBLE,
  761. 0,
  762. 0,
  763. 0,
  764. 0,
  765. ghwndApp,
  766. NULL,
  767. ghInst,
  768. NULL);
  769. #endif
  770. /* set the bmp and button size to be used for this toolbar*/
  771. toolbarAddTool(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_UP);
  772. toolbarAddTool(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_UP);
  773. /******* Make the Mark In / Mark Out toolbar ********/
  774. ghwndMark = toolbarCreateMark(ghwndApp);
  775. #if 0 //VIJR-TB
  776. CreateWindowEx(gfdwFlagsEx,
  777. szToolBarClass,
  778. NULL,
  779. WS_TABSTOP | WS_CLIPSIBLINGS | WS_CHILD |
  780. WS_VISIBLE,
  781. 0,
  782. 0,
  783. 0,
  784. 0,
  785. ghwndApp,
  786. NULL,
  787. ghInst,
  788. NULL);
  789. #endif
  790. /* set the bmp and button size to be used for this toolbar */
  791. toolbarAddTool(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_UP);
  792. toolbarAddTool(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_UP);
  793. /******* Make the Map ********/
  794. ghwndMap =
  795. CreateWindowEx(gfdwFlagsEx,
  796. TEXT("MPlayerTrackMap"),
  797. NULL,
  798. WS_GROUP | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
  799. 0,
  800. 0,
  801. 0,
  802. 0,
  803. ghwndApp,
  804. NULL,
  805. ghInst,
  806. NULL);
  807. #if DBG
  808. if( ghwndMap == NULL)
  809. {
  810. DPF0( "CreateWindowEx(MPlayerTrackMap, ...) failed: Error %d\n", GetLastError());
  811. }
  812. #endif
  813. /******* Make the Static Text ********/
  814. ghwndStatic = CreateStaticStatusWindow(ghwndApp, FALSE);
  815. #if 0 //VIJR-SB
  816. CreateWindowEx(gfdwFlagsEx,
  817. TEXT("SText"),
  818. NULL,
  819. WS_GROUP | WS_CHILD | WS_VISIBLE |
  820. WS_CLIPSIBLINGS | SS_LEFT,
  821. 0,
  822. 0,
  823. 0,
  824. 0,
  825. ghwndApp,
  826. NULL,
  827. ghInst,
  828. NULL);
  829. #endif
  830. ////SetWindowText(ghwndStatic, TEXT("Scale: Time (hh:mm)"));
  831. SendMessage(ghwndStatic, WM_SETFONT, (UINT_PTR)ghfontMap, 0);
  832. }
  833. void FAR PASCAL InitMPlayerDialog(HWND hwnd)
  834. {
  835. ghwndApp = hwnd;
  836. CreateControls();
  837. /* Get the name of the Help and ini file */
  838. LOADSTRING(IDS_INIFILE, gszMPlayerIni);
  839. LOADSTRING(IDS_HELPFILE,gszHelpFileName);
  840. LOADSTRING(IDS_HTMLHELPFILE,gszHtmlHelpFileName);
  841. ReadDefaults();
  842. }
  843. /* Use a default size or the size we pass in to size mplayer.
  844. * For PlayOnly version, this size is the MCI Window Client size.
  845. * For regular mplayer, this is the full size of the main window.
  846. * If we are inplace editing do the same as for PLayOnly.
  847. */
  848. void FAR PASCAL SetMPlayerSize(LPRECT prc)
  849. {
  850. RECT rc;
  851. UINT w=SWP_NOMOVE;
  852. if (prc && !IsRectEmpty(prc))
  853. rc = *prc;
  854. else if (gfPlayOnly || gfOle2IPEditing)
  855. rc = grcSize;
  856. else
  857. SetRect(&rc, 0, 0, giDefWidth, DEF_HEIGHT);
  858. //
  859. // if the passed rectangle has a non zero (left,top) move MPlayer
  860. // also (ie remove the SWP_NOMOVE flag)
  861. //
  862. if (rc.left != 0 || rc.top != 0)
  863. w = 0;
  864. if (gfPlayOnly || gfOle2IPEditing) {
  865. if (IsRectEmpty(&rc)) {
  866. GetClientRect(ghwndApp, &rc);
  867. rc.bottom = 0;
  868. }
  869. rc.bottom += TOOLBAR_HEIGHT;
  870. AdjustWindowRect(&rc,
  871. (DWORD)GetWindowLongPtr(ghwndApp, GWL_STYLE),
  872. GetMenu(ghwndApp) != NULL);
  873. }
  874. else
  875. if (gfWinIniChange)
  876. AdjustWindowRect(&rc,
  877. (DWORD)GetWindowLongPtr(ghwndApp, GWL_STYLE),
  878. GetMenu(ghwndApp) != NULL);
  879. SetWindowPos(ghwndApp,
  880. HWND_TOP,
  881. rc.left,
  882. rc.top,
  883. rc.right-rc.left,
  884. rc.bottom-rc.top,
  885. w | SWP_NOZORDER | SWP_NOACTIVATE);
  886. }
  887. /* InitDeviceMenuThread
  888. *
  889. * This is now executed as a separate thread.
  890. * On completion, sets the event so that the File and Device menus
  891. * can be accessed.
  892. * If, after querying the devices, we find none, post a message to
  893. * the main window to inform it.
  894. */
  895. void InitDeviceMenuThread(LPVOID pUnreferenced)
  896. {
  897. UNREFERENCED_PARAMETER(pUnreferenced);
  898. /* Wait until the command line has been scanned:
  899. */
  900. WaitForSingleObject(heventCmdLineScanned, INFINITE);
  901. /* We don't need this event any more:
  902. */
  903. CloseHandle(heventCmdLineScanned);
  904. if (ghMenu == NULL) {
  905. ghMenu = LoadMenu(ghInst, aszMPlayer);
  906. ghDeviceMenu = GetSubMenu(ghMenu, 2);
  907. }
  908. QueryDevices();
  909. BuildDeviceMenu();
  910. BuildFilter();
  911. if (gwDeviceID)
  912. FindDeviceMCI();
  913. SetEvent(heventDeviceMenuBuilt);
  914. if (gwNumDevices == 0)
  915. PostMessage(ghwndApp, WM_NOMCIDEVICES, 0, 0);
  916. ExitThread(0);
  917. }
  918. /* InitDeviceMenu
  919. *
  920. * Initialize and build the Devices menu.
  921. *
  922. * This now spins off a separate thread to enable the UI to come up
  923. * more quickly. This is especially important when there is a slow
  924. * CD device installed, though crappy CD drivers which run single threaded
  925. * at dispatch level will still give performance degradation.
  926. *
  927. * If the user selects either the File or the Device menu, the UI
  928. * must wait until the device menu has been built. Typically this
  929. * should not be longer than about 2 seconds after the app started.
  930. *
  931. */
  932. void FAR PASCAL InitDeviceMenu()
  933. {
  934. DWORD ThreadID;
  935. HANDLE hThread;
  936. static BOOL CalledOnce = FALSE;
  937. /* This should only ever be called by the main thread, so we don't need
  938. * to protect access to CalledOnce:
  939. */
  940. if (CalledOnce == FALSE)
  941. {
  942. CalledOnce = TRUE;
  943. #ifdef DEBUG
  944. if (WaitForSingleObject(heventDeviceMenuBuilt, 0) == WAIT_OBJECT_0)
  945. DPF0("Expected heventDeviceMenuBuilt to be non-signaled\n");
  946. #endif
  947. hThread = CreateThread(NULL, /* Default security attributes */
  948. 0, /* Stack size same as primary thread's */
  949. (LPTHREAD_START_ROUTINE)InitDeviceMenuThread,
  950. NULL, /* Parameter to start routine */
  951. 0, /* Thread runs immediately */
  952. &ThreadID);
  953. if(hThread)
  954. CloseHandle(hThread);
  955. else
  956. {
  957. DPF0("CreateThread failed");
  958. /* This is unlikely to happen, but the only thing to do
  959. * is set the event, so that the UI doesn't hang.
  960. */
  961. SetEvent(heventDeviceMenuBuilt);
  962. /* What if SetEvent failed?!
  963. */
  964. }
  965. }
  966. }
  967. /* WaitForDeviceMenu
  968. *
  969. * This routine calls MsgWaitForMultipleObjects instead of WaitForSingleObject
  970. * because some MCI devices do things like realizing palettes, which may
  971. * require some messages to be dispatched. Otherwise we can hit a deadlock.
  972. *
  973. * Andrew Bell (andrewbe), 8 April 1995
  974. */
  975. void WaitForDeviceMenu()
  976. {
  977. DWORD Result;
  978. while ((Result = MsgWaitForMultipleObjects(1,
  979. &heventDeviceMenuBuilt,
  980. FALSE,
  981. INFINITE,
  982. QS_ALLINPUT)) != WAIT_OBJECT_0)
  983. {
  984. MSG msg;
  985. if (Result == (DWORD)-1)
  986. {
  987. DPF0("MsgWaitForMultipleObjects failed: Error %d\n", GetLastError());
  988. return;
  989. }
  990. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  991. DispatchMessage(&msg);
  992. }
  993. }
  994. /*
  995. * SizeMPlayer()
  996. *
  997. */
  998. void FAR PASCAL SizeMPlayer()
  999. {
  1000. RECT rc;
  1001. HWND hwndPB;
  1002. if(!gfOle2IPEditing)
  1003. CreateControls();
  1004. if (gfPlayOnly) {
  1005. /* Remember our size before we shrink it so we can go back to it. */
  1006. GetWindowRect(ghwndApp, &grcSave);
  1007. SetMenu(ghwndApp, NULL);
  1008. SendMessage(ghwndTrackbar, TBM_CLEARTICS, FALSE, 0);
  1009. /* Next preserve the current size of the window as the size */
  1010. /* for the new built-in MCI window. */
  1011. if ((hwndPB = GetWindowMCI()) != NULL) {
  1012. if (IsIconic(hwndPB))
  1013. ShowWindow(hwndPB, SW_RESTORE);
  1014. GetClientRect(hwndPB, &rc);
  1015. ClientToScreen(hwndPB, (LPPOINT)&rc);
  1016. ClientToScreen(hwndPB, (LPPOINT)&rc+1);
  1017. ShowWindowMCI(FALSE);
  1018. } else { // not a windowed device?
  1019. SetRectEmpty(&rc);
  1020. }
  1021. if (ghwndMap) {
  1022. //If we are inplace editing set the toolbar control states appropriately.
  1023. if(!gfOle2IPEditing) {
  1024. ShowWindow(ghwndMap, SW_HIDE);
  1025. ShowWindow(ghwndMark, SW_HIDE);
  1026. ShowWindow(ghwndFSArrows, SW_HIDE);
  1027. ShowWindow(ghwndStatic, SW_HIDE);
  1028. ShowWindow(ghwndTrackbar, SW_SHOW);
  1029. toolbarModifyState(ghwndToolbar, BTN_EJECT, TBINDEX_MAIN, BTNST_GRAYED);
  1030. toolbarModifyState(ghwndToolbar, BTN_HOME, TBINDEX_MAIN, BTNST_GRAYED);
  1031. toolbarModifyState(ghwndToolbar, BTN_END, TBINDEX_MAIN, BTNST_GRAYED);
  1032. toolbarModifyState(ghwndToolbar, BTN_RWD, TBINDEX_MAIN, BTNST_GRAYED);
  1033. toolbarModifyState(ghwndToolbar, BTN_FWD, TBINDEX_MAIN, BTNST_GRAYED);
  1034. toolbarModifyState(ghwndMark, BTN_MARKIN, TBINDEX_MARK, BTNST_GRAYED);
  1035. toolbarModifyState(ghwndMark, BTN_MARKOUT, TBINDEX_MARK, BTNST_GRAYED);
  1036. toolbarModifyState(ghwndFSArrows, ARROW_PREV, TBINDEX_ARROWS, BTNST_GRAYED);
  1037. toolbarModifyState(ghwndFSArrows, ARROW_NEXT, TBINDEX_ARROWS, BTNST_GRAYED);
  1038. } else {
  1039. ShowWindow(ghwndMap, SW_SHOW);
  1040. ShowWindow(ghwndMark, SW_SHOW);
  1041. ShowWindow(ghwndFSArrows, SW_SHOW);
  1042. ShowWindow(ghwndStatic, SW_SHOW);
  1043. }
  1044. }
  1045. SendMessage(ghwndTrackbar, TBM_SHOWTICS, FALSE, FALSE);
  1046. CreateWindowMCI();
  1047. SetMPlayerSize(&rc);
  1048. } else {
  1049. if (ghwndMCI) {
  1050. GetClientRect(ghwndMCI, &rc);
  1051. ClientToScreen(ghwndMCI, (LPPOINT)&rc);
  1052. ClientToScreen(ghwndMCI, (LPPOINT)&rc+1);
  1053. /*
  1054. ** Make sure our hook proc doesn't post IDM_CLOSE!
  1055. ** The WM_CLOSE message will set the playback window back
  1056. ** to the video playback window by calling SetWindowMCI(NULL);
  1057. */
  1058. gfSeenPBCloseMsg = TRUE;
  1059. SendMessage(ghwndMCI, WM_CLOSE, 0, 0);
  1060. /*
  1061. ** Subclass the real video window now. This will also set
  1062. ** gfSeenPBCloseMsg to FALSE.
  1063. */
  1064. SubClassMCIWindow();
  1065. } else {
  1066. GetWindowRect(ghwndApp,&rc);
  1067. OffsetRect(&grcSave, rc.left - grcSave.left,
  1068. rc.top - grcSave.top);
  1069. SetRectEmpty(&rc);
  1070. }
  1071. SendMessage(ghwndTrackbar, TBM_SHOWTICS, TRUE, FALSE);
  1072. ShowWindow(ghwndMap, SW_SHOW);
  1073. ShowWindow(ghwndMark, SW_SHOW);
  1074. ShowWindow(ghwndStatic, SW_SHOW);
  1075. /* If we remembered a size, use it, else use default */
  1076. SetMPlayerSize(&grcSave);
  1077. InvalidateRect(ghwndStatic, NULL, TRUE); // why is this necessary?
  1078. if (gwDeviceID && (gwDeviceType & DTMCI_CANWINDOW)) {
  1079. /* make the playback window the size our MCIWindow was and */
  1080. /* show the playback window and stretch to it ? */
  1081. if (!IsRectEmpty(&rc))
  1082. PutWindowMCI(&rc);
  1083. SmartWindowPosition(GetWindowMCI(), ghwndApp, gfOle2Open);
  1084. ShowWindowMCI(TRUE);
  1085. SetForegroundWindow(ghwndApp);
  1086. }
  1087. ShowWindow(ghwndFSArrows, SW_SHOW);
  1088. }
  1089. InvalidateRect(ghwndApp, NULL, TRUE);
  1090. gfValidCaption = FALSE;
  1091. gwStatus = (UINT)(-1); // force a full update
  1092. UpdateDisplay();
  1093. }
  1094. /*
  1095. * pKeyBuf = LoadProfileKeys(lszProfile, lszSection)
  1096. *
  1097. * Load the keywords from the <szSection> section of the Windows profile
  1098. * file named <szProfile>. Allocate buffer space and return a pointer to it.
  1099. * On failure, return NULL.
  1100. *
  1101. * The INT pointed to by pSize will be filled in with the size of the
  1102. * buffer returned, so that checks for corruption can be made when it's freed.
  1103. */
  1104. PTSTR NEAR PASCAL LoadProfileKeys(
  1105. LPTSTR lszProfile, /* the name of the profile file to access */
  1106. LPTSTR lszSection, /* the section name to look under */
  1107. PUINT pSize)
  1108. {
  1109. PTSTR pKeyBuf; /* pointer to the section's key list */
  1110. PTSTR pKeyBufNew;
  1111. UINT wSize; /* the size of <pKeyBuf> */
  1112. ////DPF("LoadProfileKeys('%"DTS"', '%"DTS"')\n", (LPTSTR) lszProfile, (LPTSTR)lszSection);
  1113. /*
  1114. * Load all keynames present in the <lszSection> section of the profile
  1115. * file named <lszProfile>.
  1116. *
  1117. */
  1118. wSize = 256; /* make a wild initial guess */
  1119. pKeyBuf = NULL; /* the key list is initially empty */
  1120. do {
  1121. /* (Re)alloc the space to load the keynames into */
  1122. if (pKeyBuf == NULL)
  1123. pKeyBuf = AllocMem(wSize);
  1124. else {
  1125. pKeyBufNew = ReallocMem( (HANDLE)pKeyBuf, wSize, wSize + 256);
  1126. if (NULL == pKeyBufNew) {
  1127. FreeMem((HANDLE)pKeyBuf, wSize);
  1128. }
  1129. pKeyBuf = pKeyBufNew;
  1130. wSize += 256;
  1131. }
  1132. if (pKeyBuf == NULL) /* the (re)alloc failed */
  1133. return NULL;
  1134. /*
  1135. * THIS IS A WINDOWS BUG!!! It returns size minus two!!
  1136. * (The same feature is present in Windows/NT)
  1137. */
  1138. } while (GetPrivateProfileString(lszSection, NULL, aszNULL, pKeyBuf, wSize/sizeof(TCHAR),
  1139. lszProfile) >= (wSize/sizeof(TCHAR) - 2));
  1140. if (pSize)
  1141. *pSize = wSize;
  1142. return pKeyBuf;
  1143. }
  1144. /*
  1145. * QueryDevices(void)
  1146. *
  1147. * Find out what devices are available to the player. and initialize the
  1148. * garMciDevices[] array.
  1149. *
  1150. */
  1151. void NEAR PASCAL QueryDevices(void)
  1152. {
  1153. PTSTR pch;
  1154. PTSTR pchDevices;
  1155. PTSTR pchExtensions;
  1156. PTSTR pchDevice;
  1157. PTSTR pchExt;
  1158. TCHAR ach[1024]; /*1024 is the maximum buffer size for a wsprintf call*/
  1159. UINT wDeviceType; /* Return value from DeviceTypeMCI() */
  1160. INT DevicesSize;
  1161. INT ExtensionsSize;
  1162. if (gwNumDevices > 0)
  1163. return;
  1164. /*
  1165. * make device zero be the autoopen device.
  1166. * its device name will be "" and the files it supports will be "*.*"
  1167. */
  1168. LOADSTRING(IDS_ALLFILES, ach);
  1169. garMciDevices[0].wDeviceType = DTMCI_CANPLAY | DTMCI_FILEDEV;
  1170. garMciDevices[0].szDevice = aszNULL;
  1171. garMciDevices[0].szDeviceName = AllocStr(ach);
  1172. garMciDevices[0].szFileExt = aszAllFiles;
  1173. gwNumDevices = 0;
  1174. /* Load the SYSTEM.INI [MCI] section */
  1175. /* If the user specified a device to open, build a string containing
  1176. * that device alone, and don't bother looking in the registry
  1177. * (or system.ini in the case of Win95) for the MCI devices.
  1178. */
  1179. if (*gachOpenDevice)
  1180. {
  1181. LPTSTR pDevice;
  1182. DWORD DeviceLength;
  1183. pDevice = gachOpenDevice;
  1184. DeviceLength = STRING_BYTE_COUNT(pDevice);
  1185. DevicesSize = ((DeviceLength + 1) * sizeof *pchDevice);
  1186. if (pchDevices = AllocMem(DevicesSize))
  1187. CopyMemory(pchDevices, pDevice, DevicesSize);
  1188. }
  1189. else
  1190. {
  1191. pchDevices = AllocMem(DevicesSize = 256);
  1192. if (pchDevices)
  1193. QueryDevicesMCI(pchDevices, DevicesSize);
  1194. }
  1195. pchExtensions = LoadProfileKeys(aszWinIni, gszWinIniSection, &ExtensionsSize);
  1196. if (pchExtensions == NULL || pchDevices == NULL) {
  1197. DPF("unable to load extensions section\n");
  1198. if (pchExtensions)
  1199. FreeMem(pchExtensions, ExtensionsSize);
  1200. if (pchDevices)
  1201. FreeMem(pchDevices, DevicesSize);
  1202. return;
  1203. }
  1204. /*
  1205. * Search through the list of device names found in SYSTEM.INI, looking for
  1206. * keywords; if profile was not found, then *gpSystemIniKeyBuf == 0
  1207. *
  1208. * in SYSTEM.INI:
  1209. *
  1210. * [MCI]
  1211. * device = driver.drv
  1212. *
  1213. * in WIN.INI:
  1214. *
  1215. * [MCI Extensions]
  1216. * xyz = device
  1217. *
  1218. * in MPLAYER.INI:
  1219. *
  1220. * [Devices]
  1221. * device = <device type>, <device name>
  1222. *
  1223. * NOTE: The storage of device information in MPLAYER.INI has been nuked
  1224. * for NT - it may speed things up, but where we are changing
  1225. * devices regularly after initial setup this is a pain, as deleting
  1226. * the INI file regularly gets stale real quick.
  1227. *
  1228. */
  1229. for (pchDevice = pchDevices;
  1230. *pchDevice;
  1231. pchDevice += STRLEN(pchDevice)+1) {
  1232. //
  1233. // we have no info in MPLAYER.INI about this device, so load it and
  1234. // ask it.
  1235. //
  1236. wDeviceType = DeviceTypeMCI(pchDevice, ach, CHAR_COUNT(ach));
  1237. //
  1238. // if we don't like this device, don't store it
  1239. //
  1240. if (wDeviceType == DTMCI_ERROR ||
  1241. wDeviceType == DTMCI_IGNOREDEVICE ||
  1242. !(wDeviceType & DTMCI_CANPLAY)) {
  1243. continue;
  1244. }
  1245. gwNumDevices++;
  1246. garMciDevices[gwNumDevices].wDeviceType = wDeviceType;
  1247. garMciDevices[gwNumDevices].szDevice = AllocStr(pchDevice);
  1248. garMciDevices[gwNumDevices].szDeviceName = AllocStr(ach);
  1249. garMciDevices[gwNumDevices].szFileExt = NULL;
  1250. //
  1251. // now look in the [mci extensions] section in WIN.INI to find
  1252. // out the files this device deals with.
  1253. //
  1254. for (pchExt = pchExtensions; *pchExt; pchExt += STRLEN(pchExt)+1) {
  1255. GetProfileString(gszWinIniSection, pchExt, aszNULL, ach, CHAR_COUNT(ach));
  1256. if (lstrcmpi(ach, pchDevice) == 0) {
  1257. if ((pch = garMciDevices[gwNumDevices].szFileExt) != NULL) {
  1258. wsprintf(ach, aszFormatExts, (LPTSTR)pch, (LPTSTR)pchExt);
  1259. CharLowerBuff(ach, STRLEN(ach)); // Make sure it's lower case so
  1260. // we can use STRSTR if necessary.
  1261. FreeStr((HANDLE)pch);
  1262. garMciDevices[gwNumDevices].szFileExt = AllocStr(ach);
  1263. }
  1264. else {
  1265. wsprintf(ach, aszFormatExt, (LPTSTR)pchExt);
  1266. CharLowerBuff(ach, STRLEN(ach));
  1267. garMciDevices[gwNumDevices].szFileExt = AllocStr(ach);
  1268. }
  1269. }
  1270. }
  1271. //
  1272. // !!!only do this if the device deals with files.
  1273. //
  1274. if (garMciDevices[gwNumDevices].szFileExt == NULL &&
  1275. (garMciDevices[gwNumDevices].wDeviceType & DTMCI_FILEDEV))
  1276. garMciDevices[gwNumDevices].szFileExt = aszAllFiles;
  1277. #ifdef DEBUG
  1278. DPF1("Device:%"DTS"; Name:%"DTS"; Type:%d; Extension:%"DTS"\n",
  1279. (LPTSTR)garMciDevices[gwNumDevices].szDevice,
  1280. (LPTSTR)garMciDevices[gwNumDevices].szDeviceName,
  1281. garMciDevices[gwNumDevices].wDeviceType,
  1282. garMciDevices[gwNumDevices].szFileExt
  1283. ? (LPTSTR)garMciDevices[gwNumDevices].szFileExt
  1284. : aszNULL);
  1285. #endif
  1286. }
  1287. /* all done with the system.ini keys so free them */
  1288. FreeMem(pchDevices, DevicesSize);
  1289. FreeMem(pchExtensions, ExtensionsSize);
  1290. }
  1291. /*
  1292. * BuildDeviceMenu()
  1293. *
  1294. * Insert all devices into the device menu, we only want devices that
  1295. * support the MCI_PLAY command.
  1296. *
  1297. * Add "..." to the menu for devices that support files.
  1298. *
  1299. */
  1300. void NEAR PASCAL BuildDeviceMenu()
  1301. {
  1302. int i;
  1303. TCHAR ach[128];
  1304. if (gwNumDevices == 0)
  1305. return;
  1306. DeleteMenu(ghDeviceMenu, IDM_NONE, MF_BYCOMMAND);
  1307. //
  1308. // start at device '1' because device 0 is the auto open device
  1309. //
  1310. for (i=1; i<=(int)gwNumDevices; i++) {
  1311. //
  1312. // we only care about devices that can play!
  1313. //
  1314. if (!(garMciDevices[i].wDeviceType & DTMCI_CANPLAY))
  1315. continue;
  1316. if (garMciDevices[i].wDeviceType & DTMCI_SIMPLEDEV)
  1317. wsprintf(ach, aszDeviceMenuSimpleFormat, i, (LPTSTR)garMciDevices[i].szDeviceName);
  1318. else if (garMciDevices[i].wDeviceType & DTMCI_FILEDEV)
  1319. wsprintf(ach, aszDeviceMenuCompoundFormat, i, (LPTSTR)garMciDevices[i].szDeviceName);
  1320. else
  1321. continue;
  1322. InsertMenu(ghDeviceMenu, i-1, MF_STRING|MF_BYPOSITION, IDM_DEVICE0+i, ach);
  1323. }
  1324. }
  1325. /*
  1326. * BuildFilter()
  1327. *
  1328. * build the filter to be used with GetOpenFileName()
  1329. *
  1330. * the filter will look like this...
  1331. *
  1332. * DEVICE1 (*.111)
  1333. * DEVICE2 (*.222)
  1334. *
  1335. * DEVICEn (*.333)
  1336. *
  1337. * All Files (*.*)
  1338. *
  1339. */
  1340. void NEAR PASCAL BuildFilter()
  1341. {
  1342. UINT w;
  1343. PTSTR pch;
  1344. PTSTR pchFilterNew;
  1345. #define INITIAL_SIZE ( 8192 * sizeof( TCHAR ) )
  1346. pch = gpchFilter = AllocMem( INITIAL_SIZE ); //!!!
  1347. if (gpchFilter == NULL)
  1348. return; //!!!
  1349. for (w=1; w<=gwNumDevices; w++)
  1350. {
  1351. if (garMciDevices[w].wDeviceType == DTMCI_ERROR ||
  1352. garMciDevices[w].wDeviceType == DTMCI_IGNOREDEVICE)
  1353. continue;
  1354. if (garMciDevices[w].wDeviceType & DTMCI_FILEDEV ||
  1355. lstrcmpi(TEXT("CDAudio"), garMciDevices[w].szDevice) == 0) //Hack!!! This will list *.cda files
  1356. //in the open dialog box. MCI by itself
  1357. //does not handle playing of *.cda files
  1358. //but media player does locally.
  1359. {
  1360. wsprintf(pch, aszFormatFilter,
  1361. (LPTSTR)garMciDevices[w].szDeviceName,
  1362. (LPTSTR)garMciDevices[w].szFileExt);
  1363. pch += STRLEN(pch)+1;
  1364. lstrcpy(pch, garMciDevices[w].szFileExt);
  1365. pch += STRLEN(pch)+1;
  1366. }
  1367. else
  1368. {
  1369. lstrcpy(pch, garMciDevices[w].szDeviceName);
  1370. pch += STRLEN(pch)+1;
  1371. lstrcpy(pch, aszBlank);
  1372. pch += STRLEN(pch)+1;
  1373. }
  1374. }
  1375. //
  1376. // now add "All Files" (device 0) last
  1377. //
  1378. wsprintf(pch, aszFormatFilter, (LPTSTR)garMciDevices[0].szDeviceName, (LPTSTR)garMciDevices[0].szFileExt);
  1379. pch += STRLEN(pch)+1;
  1380. lstrcpy(pch, garMciDevices[0].szFileExt);
  1381. pch += STRLEN(pch)+1;
  1382. //
  1383. // all done!
  1384. //
  1385. *pch++ = 0;
  1386. //
  1387. // realloc this down to size
  1388. //
  1389. pchFilterNew = ReallocMem( gpchFilter,
  1390. INITIAL_SIZE,
  1391. (UINT)(pch-gpchFilter)*sizeof(*pch) );
  1392. if (NULL == pchFilterNew) {
  1393. FreeMem(gpchFilter, 0);
  1394. }
  1395. gpchFilter = pchFilterNew;
  1396. }
  1397. /* Call every time we open a different device to get the default options */
  1398. void FAR PASCAL ReadOptions(void)
  1399. {
  1400. TCHAR ach[20];
  1401. if (gwDeviceID == (UINT)0)
  1402. return;
  1403. /* Get the options and scale style to be used for this device */
  1404. GetDeviceNameMCI(ach, BYTE_COUNT(ach));
  1405. ReadRegistryData(aszOptionsSection, ach, NULL, (LPBYTE)&gwOptions, sizeof gwOptions);
  1406. if (gwOptions == 0)
  1407. gwOptions |= OPT_BAR | OPT_TITLE | OPT_BORDER;
  1408. gwOptions |= OPT_PLAY; /* Always default to play in place. */
  1409. gwCurScale = gwOptions & OPT_SCALE;
  1410. switch (gwCurScale) {
  1411. case ID_TIME:
  1412. case ID_FRAMES:
  1413. case ID_TRACKS:
  1414. break;
  1415. default:
  1416. /* Default CD scale to tracks rather than time.
  1417. * Much more sensible:
  1418. */
  1419. if ((gwDeviceType & DTMCI_DEVICE) == DTMCI_CDAUDIO)
  1420. gwCurScale = ID_TRACKS;
  1421. else
  1422. gwCurScale = ID_TIME;
  1423. break;
  1424. }
  1425. }
  1426. /*
  1427. * ReadDefaults()
  1428. *
  1429. * Read the user defaults from the MPLAYER.INI file.
  1430. *
  1431. */
  1432. void NEAR PASCAL ReadDefaults(void)
  1433. {
  1434. TCHAR sz[20];
  1435. TCHAR *pch;
  1436. int x,y,w,h;
  1437. UINT f;
  1438. *sz = TEXT('\0');
  1439. ReadRegistryData(aszOptionsSection, aszDisplayPosition, NULL, (LPBYTE)sz, BYTE_COUNT(sz));
  1440. x = ATOI(sz);
  1441. pch = sz;
  1442. while (*pch && *pch++ != TEXT(','))
  1443. ;
  1444. if (*pch) {
  1445. y = ATOI(pch);
  1446. while (*pch && *pch++ != TEXT(','))
  1447. ;
  1448. if (*pch) {
  1449. w = ATOI(pch);
  1450. while (*pch && *pch++ != TEXT(','))
  1451. ;
  1452. if (*pch) {
  1453. h = ATOI(pch);
  1454. f = SWP_NOACTIVATE | SWP_NOZORDER;
  1455. if (w == 0 || h == 0)
  1456. f |= SWP_NOSIZE;
  1457. if (!ghInstPrev && x >= 0 && y >= 0
  1458. && x < GetSystemMetrics(SM_CXSCREEN)
  1459. && y < GetSystemMetrics(SM_CYSCREEN)) {
  1460. SetWindowPos(ghwndApp, NULL, x, y, w, h, f);
  1461. // Remember this so even if we come up in teeny mode and
  1462. // someone exits, it'll have these numbers to save
  1463. SetRect(&grcSave, x, y, x + w, y + h);
  1464. } else {
  1465. SetWindowPos(ghwndApp, NULL, 0, 0, w, h, f | SWP_NOMOVE);
  1466. }
  1467. }
  1468. }
  1469. }
  1470. }
  1471. /* Call every time we close a device to save its options */
  1472. void FAR PASCAL WriteOutOptions(void)
  1473. {
  1474. if (gwCurDevice) {
  1475. /* Put the scale in the proper bits of the Options */
  1476. gwOptions = (gwOptions & ~OPT_SCALE) | gwCurScale;
  1477. WriteRegistryData(aszOptionsSection,
  1478. garMciDevices[gwCurDevice].szDevice, REG_DWORD, (LPBYTE)&gwOptions, sizeof gwOptions);
  1479. }
  1480. }
  1481. void FAR PASCAL WriteOutPosition(void)
  1482. {
  1483. TCHAR sz[20];
  1484. WINDOWPLACEMENT wp;
  1485. //
  1486. // Only the first instance will save settings.
  1487. // Play only mode will save the remembered rect for when it was in
  1488. // regular mode. If no rect is remembered, don't write anything.
  1489. //
  1490. if (ghInstPrev || (gfPlayOnly && grcSave.left == 0))
  1491. return;
  1492. /* Save the size it was when it was Normal because the next time */
  1493. /* MPlayer comes up, it won't be in reduced mode. */
  1494. /* Only valid if some number has been saved. */
  1495. if (gfPlayOnly)
  1496. wp.rcNormalPosition = grcSave;
  1497. else {
  1498. wp.length = sizeof(WINDOWPLACEMENT);
  1499. GetWindowPlacement(ghwndApp, &wp);
  1500. }
  1501. wsprintf(sz, aszPositionFormat,
  1502. wp.rcNormalPosition.left,
  1503. wp.rcNormalPosition.top,
  1504. wp.rcNormalPosition.right - wp.rcNormalPosition.left,
  1505. wp.rcNormalPosition.bottom - wp.rcNormalPosition.top);
  1506. WriteRegistryData(aszOptionsSection, aszDisplayPosition, REG_SZ, (LPBYTE)sz, STRING_BYTE_COUNT(sz));
  1507. }
  1508. BOOL FAR PASCAL GetIntlSpecs()
  1509. {
  1510. TCHAR szTmp[2];
  1511. szTmp[0] = chDecimal;
  1512. szTmp[1] = 0;
  1513. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, szTmp, CHAR_COUNT(szTmp));
  1514. chDecimal = szTmp[0];
  1515. szTmp[0] = chTime;
  1516. szTmp[1] = 0;
  1517. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, szTmp, CHAR_COUNT(szTmp));
  1518. chTime = szTmp[0];
  1519. szTmp[0] = chLzero;
  1520. szTmp[1] = 0;
  1521. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILZERO, szTmp, CHAR_COUNT(szTmp));
  1522. chLzero = szTmp[0];
  1523. return TRUE;
  1524. }
  1525. /*----------------------------------------------------------------------------*\
  1526. | SmartWindowPosition (HWND hWndDlg, HWND hWndShow)
  1527. |
  1528. | Description:
  1529. | This function attempts to position a dialog box so that it
  1530. | does not obscure the hWndShow window. This function is
  1531. | typically called during WM_INITDIALOG processing.
  1532. |
  1533. | Arguments:
  1534. | hWndDlg handle of the soon to be displayed dialog
  1535. | hWndShow handle of the window to keep visible
  1536. |
  1537. | Returns:
  1538. | 1 if the windows overlap and positions were adjusted
  1539. | 0 if the windows don't overlap
  1540. |
  1541. \*----------------------------------------------------------------------------*/
  1542. void FAR PASCAL SmartWindowPosition (HWND hWndDlg, HWND hWndShow, BOOL fForce)
  1543. {
  1544. RECT rc, rcDlg, rcShow;
  1545. int iHeight, iWidth;
  1546. int dxScreen = GetSystemMetrics(SM_CXSCREEN);
  1547. int dyScreen = GetSystemMetrics(SM_CYSCREEN);
  1548. if (hWndDlg == NULL || hWndShow == NULL)
  1549. return;
  1550. GetWindowRect(hWndDlg, &rcDlg);
  1551. GetWindowRect(hWndShow, &rcShow);
  1552. InflateRect (&rcShow, 5, 5); // allow a small border
  1553. if (fForce || IntersectRect(&rc, &rcDlg, &rcShow)){
  1554. /* the two do intersect, now figure out where to place */
  1555. /* this dialog window. Try to go below the Show window */
  1556. /* first and then to the right, top and left. */
  1557. /* get the size of this dialog */
  1558. iHeight = rcDlg.bottom - rcDlg.top;
  1559. iWidth = rcDlg.right - rcDlg.left;
  1560. if ((rcShow.top - iHeight - 1) > 0){
  1561. /* will fit on top, handle that */
  1562. rc.top = rcShow.top - iHeight - 1;
  1563. rc.left = (((rcShow.right - rcShow.left)/2) + rcShow.left)
  1564. - (iWidth/2);
  1565. } else if ((rcShow.bottom + iHeight + 1) < dyScreen){
  1566. /* will fit on bottom, go for it */
  1567. rc.top = rcShow.bottom + 1;
  1568. rc.left = (((rcShow.right - rcShow.left)/2) + rcShow.left)
  1569. - (iWidth/2);
  1570. } else if ((rcShow.right + iWidth + 1) < dxScreen){
  1571. /* will fit to right, go for it */
  1572. rc.left = rcShow.right + 1;
  1573. rc.top = (((rcShow.bottom - rcShow.top)/2) + rcShow.top)
  1574. - (iHeight/2);
  1575. } else if ((rcShow.left - iWidth - 1) > 0){
  1576. /* will fit to left, do it */
  1577. rc.left = rcShow.left - iWidth - 1;
  1578. rc.top = (((rcShow.bottom - rcShow.top)/2) + rcShow.top)
  1579. - (iHeight/2);
  1580. } else {
  1581. /* we are hosed, they cannot be placed so that there is */
  1582. /* no overlap anywhere. */
  1583. /* just leave it alone */
  1584. rc = rcDlg;
  1585. }
  1586. /* make any adjustments necessary to keep it on the screen */
  1587. if (rc.left < 0)
  1588. rc.left = 0;
  1589. else if ((rc.left + iWidth) > dxScreen)
  1590. rc.left = dxScreen - iWidth;
  1591. if (rc.top < 0)
  1592. rc.top = 0;
  1593. else if ((rc.top + iHeight) > dyScreen)
  1594. rc.top = dyScreen - iHeight;
  1595. SetWindowPos(hWndDlg, NULL, rc.left, rc.top, 0, 0,
  1596. SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  1597. return;
  1598. } // if the windows overlap by default
  1599. }