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.

380 lines
9.8 KiB

  1. //------------------------------------------------------------------------------
  2. // File: CProp.cpp
  3. //
  4. // Desc: DirectShow base classes - implements CBasePropertyPage class.
  5. //
  6. // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
  7. //------------------------------------------------------------------------------
  8. #include <streams.h>
  9. // Constructor for the base property page class. As described in the header
  10. // file we must be initialised with dialog and title resource identifiers.
  11. // The class supports IPropertyPage and overrides AddRef and Release calls
  12. // to keep track of the reference counts. When the last count is released
  13. // we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces
  14. // previously obtained by the property page when it had SetObjects called
  15. CBasePropertyPage::CBasePropertyPage(TCHAR *pName, // Debug only name
  16. LPUNKNOWN pUnk, // COM Delegator
  17. int DialogId, // Resource ID
  18. int TitleId) : // To get tital
  19. CUnknown(pName,pUnk),
  20. m_DialogId(DialogId),
  21. m_TitleId(TitleId),
  22. m_hwnd(NULL),
  23. m_Dlg(NULL),
  24. m_pPageSite(NULL),
  25. m_bObjectSet(FALSE),
  26. m_bDirty(FALSE)
  27. {
  28. }
  29. #ifdef UNICODE
  30. CBasePropertyPage::CBasePropertyPage(CHAR *pName, // Debug only name
  31. LPUNKNOWN pUnk, // COM Delegator
  32. int DialogId, // Resource ID
  33. int TitleId) : // To get tital
  34. CUnknown(pName,pUnk),
  35. m_DialogId(DialogId),
  36. m_TitleId(TitleId),
  37. m_hwnd(NULL),
  38. m_Dlg(NULL),
  39. m_pPageSite(NULL),
  40. m_bObjectSet(FALSE),
  41. m_bDirty(FALSE)
  42. {
  43. }
  44. #endif
  45. // Increment our reference count
  46. STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef()
  47. {
  48. LONG lRef = InterlockedIncrement(&m_cRef);
  49. ASSERT(lRef > 0);
  50. return max(ULONG(m_cRef),1ul);
  51. }
  52. // Release a reference count and protect against reentrancy
  53. STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease()
  54. {
  55. // If the reference count drops to zero delete ourselves
  56. if (InterlockedDecrement(&m_cRef) == 0) {
  57. m_cRef++;
  58. SetPageSite(NULL);
  59. SetObjects(0,NULL);
  60. delete this;
  61. return ULONG(0);
  62. } else {
  63. return max(ULONG(m_cRef),1ul);
  64. }
  65. }
  66. // Expose our IPropertyPage interface
  67. STDMETHODIMP
  68. CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,void **ppv)
  69. {
  70. if (riid == IID_IPropertyPage) {
  71. return GetInterface((IPropertyPage *)this,ppv);
  72. } else {
  73. return CUnknown::NonDelegatingQueryInterface(riid,ppv);
  74. }
  75. }
  76. // Get the page info so that the page site can size itself
  77. STDMETHODIMP CBasePropertyPage::GetPageInfo(LPPROPPAGEINFO pPageInfo)
  78. {
  79. CheckPointer(pPageInfo,E_POINTER);
  80. WCHAR wszTitle[STR_MAX_LENGTH];
  81. WideStringFromResource(wszTitle,m_TitleId);
  82. // Allocate dynamic memory for the property page title
  83. LPOLESTR pszTitle;
  84. HRESULT hr = AMGetWideString(wszTitle, &pszTitle);
  85. if (FAILED(hr)) {
  86. NOTE("No caption memory");
  87. return hr;
  88. }
  89. pPageInfo->cb = sizeof(PROPPAGEINFO);
  90. pPageInfo->pszTitle = pszTitle;
  91. pPageInfo->pszDocString = NULL;
  92. pPageInfo->pszHelpFile = NULL;
  93. pPageInfo->dwHelpContext = 0;
  94. // Set defaults in case GetDialogSize fails
  95. pPageInfo->size.cx = 340;
  96. pPageInfo->size.cy = 150;
  97. GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size);
  98. return NOERROR;
  99. }
  100. // Handles the messages for our property window
  101. INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
  102. UINT uMsg,
  103. WPARAM wParam,
  104. LPARAM lParam)
  105. {
  106. CBasePropertyPage *pPropertyPage;
  107. switch (uMsg) {
  108. case WM_INITDIALOG:
  109. SetWindowLongPtr(hwnd, DWLP_USER, lParam);
  110. // This pointer may be NULL when calculating size
  111. pPropertyPage = (CBasePropertyPage *) lParam;
  112. if (pPropertyPage == NULL) {
  113. return (LRESULT) 1;
  114. }
  115. pPropertyPage->m_Dlg = hwnd;
  116. }
  117. // This pointer may be NULL when calculating size
  118. pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
  119. if (pPropertyPage == NULL) {
  120. return (LRESULT) 1;
  121. }
  122. return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam);
  123. }
  124. // Tells us the object that should be informed of the property changes
  125. STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,LPUNKNOWN *ppUnk)
  126. {
  127. if (cObjects == 1) {
  128. if ((ppUnk == NULL) || (*ppUnk == NULL)) {
  129. return E_POINTER;
  130. }
  131. // Set a flag to say that we have set the Object
  132. m_bObjectSet = TRUE ;
  133. return OnConnect(*ppUnk);
  134. } else if (cObjects == 0) {
  135. // Set a flag to say that we have not set the Object for the page
  136. m_bObjectSet = FALSE ;
  137. return OnDisconnect();
  138. }
  139. DbgBreak("No support for more than one object");
  140. return E_UNEXPECTED;
  141. }
  142. // Create the window we will use to edit properties
  143. STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent,
  144. LPCRECT pRect,
  145. BOOL fModal)
  146. {
  147. CheckPointer(pRect,E_POINTER);
  148. // Return failure if SetObject has not been called.
  149. if (m_bObjectSet == FALSE) {
  150. return E_UNEXPECTED;
  151. }
  152. if (m_hwnd) {
  153. return E_UNEXPECTED;
  154. }
  155. m_hwnd = CreateDialogParam(g_hInst,
  156. MAKEINTRESOURCE(m_DialogId),
  157. hwndParent,
  158. DialogProc,
  159. (LPARAM) this);
  160. if (m_hwnd == NULL) {
  161. return E_OUTOFMEMORY;
  162. }
  163. OnActivate();
  164. Move(pRect);
  165. return Show(SW_SHOWNORMAL);
  166. }
  167. // Set the position of the property page
  168. STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect)
  169. {
  170. CheckPointer(pRect,E_POINTER);
  171. if (m_hwnd == NULL) {
  172. return E_UNEXPECTED;
  173. }
  174. MoveWindow(m_hwnd, // Property page handle
  175. pRect->left, // x coordinate
  176. pRect->top, // y coordinate
  177. WIDTH(pRect), // Overall window width
  178. HEIGHT(pRect), // And likewise height
  179. TRUE); // Should we repaint it
  180. return NOERROR;
  181. }
  182. // Display the property dialog
  183. STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow)
  184. {
  185. // Have we been activated yet
  186. if (m_hwnd == NULL) {
  187. return E_UNEXPECTED;
  188. }
  189. // Ignore wrong show flags
  190. if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) {
  191. return E_INVALIDARG;
  192. }
  193. ShowWindow(m_hwnd,nCmdShow);
  194. InvalidateRect(m_hwnd,NULL,TRUE);
  195. return NOERROR;
  196. }
  197. // Destroy the property page dialog
  198. STDMETHODIMP CBasePropertyPage::Deactivate(void)
  199. {
  200. if (m_hwnd == NULL) {
  201. return E_UNEXPECTED;
  202. }
  203. // Remove WS_EX_CONTROLPARENT before DestroyWindow call
  204. DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
  205. dwStyle = dwStyle & (~WS_EX_CONTROLPARENT);
  206. // Set m_hwnd to be NULL temporarily so the message handler
  207. // for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT
  208. // style back in
  209. HWND hwnd = m_hwnd;
  210. m_hwnd = NULL;
  211. SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle);
  212. m_hwnd = hwnd;
  213. OnDeactivate();
  214. // Destroy the dialog window
  215. DestroyWindow(m_hwnd);
  216. m_hwnd = NULL;
  217. return NOERROR;
  218. }
  219. // Tells the application property page site
  220. STDMETHODIMP CBasePropertyPage::SetPageSite(LPPROPERTYPAGESITE pPageSite)
  221. {
  222. if (pPageSite) {
  223. if (m_pPageSite) {
  224. return E_UNEXPECTED;
  225. }
  226. m_pPageSite = pPageSite;
  227. m_pPageSite->AddRef();
  228. } else {
  229. if (m_pPageSite == NULL) {
  230. return E_UNEXPECTED;
  231. }
  232. m_pPageSite->Release();
  233. m_pPageSite = NULL;
  234. }
  235. return NOERROR;
  236. }
  237. // Apply any changes so far made
  238. STDMETHODIMP CBasePropertyPage::Apply()
  239. {
  240. // In ActiveMovie 1.0 we used to check whether we had been activated or
  241. // not. This is too constrictive. Apply should be allowed as long as
  242. // SetObject was called to set an object. So we will no longer check to
  243. // see if we have been activated (ie., m_hWnd != NULL), but instead
  244. // make sure that m_bObjectSet is TRUE (ie., SetObject has been called).
  245. if (m_bObjectSet == FALSE) {
  246. return E_UNEXPECTED;
  247. }
  248. // Must have had a site set
  249. if (m_pPageSite == NULL) {
  250. return E_UNEXPECTED;
  251. }
  252. // Has anything changed
  253. if (m_bDirty == FALSE) {
  254. return NOERROR;
  255. }
  256. // Commit derived class changes
  257. HRESULT hr = OnApplyChanges();
  258. if (SUCCEEDED(hr)) {
  259. m_bDirty = FALSE;
  260. }
  261. return hr;
  262. }
  263. // Base class definition for message handling
  264. INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  265. {
  266. // we would like the TAB key to move around the tab stops in our property
  267. // page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT
  268. // style behind our back, so we need to switch it back on now behind its
  269. // back. Otherwise the tab key will be useless in every page.
  270. //
  271. CBasePropertyPage *pPropertyPage;
  272. {
  273. pPropertyPage = (CBasePropertyPage *) GetWindowLongPtr(hwnd, DWLP_USER);
  274. if (pPropertyPage->m_hwnd == NULL) {
  275. return 0;
  276. }
  277. switch (uMsg) {
  278. case WM_STYLECHANGING:
  279. if (wParam == GWL_EXSTYLE) {
  280. LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam;
  281. lpss->styleNew |= WS_EX_CONTROLPARENT;
  282. return 0;
  283. }
  284. }
  285. }
  286. return DefWindowProc(hwnd,uMsg,wParam,lParam);
  287. }