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.

532 lines
13 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved
  3. Module Name:
  4. RsRecall.cpp
  5. Abstract:
  6. Main module file - defines the overall COM server.
  7. Author:
  8. Rohde Wakefield [rohde] 04-Mar-1997
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "aclapi.h"
  13. BEGIN_OBJECT_MAP( ObjectMap )
  14. OBJECT_ENTRY( CLSID_CFsaRecallNotifyClient, CNotifyClient )
  15. END_OBJECT_MAP()
  16. const CString regString = TEXT( "reg" );
  17. const CString unregString = TEXT( "unreg" );
  18. HRESULT RegisterServer(void);
  19. HRESULT UnregisterServer(void);
  20. #ifdef _USRDLL
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Setup to use if we are a DLL /////////////////////////////////////////////
  23. /////////////////////////////////////////////////////////////////////////////
  24. #define RecRegId IDR_CNotifyClientAppDll
  25. /////////////////////////////////////////////////////////////////////////////
  26. // Used to determine whether the DLL can be unloaded by OLE
  27. STDAPI DllCanUnloadNow(void)
  28. {
  29. TRACEFNHR( "DllCanUnloadNow" );
  30. AFX_MANAGE_STATE( AfxGetStaticModuleState( ) );
  31. hrRet = (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
  32. return( hrRet );
  33. }
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Returns a class factory to create an object of the requested type
  36. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  37. {
  38. TRACEFNHR( "DllGetClassObject" );
  39. AFX_MANAGE_STATE( AfxGetStaticModuleState( ) );
  40. hrRet = _Module.GetClassObject(rclsid, riid, ppv);
  41. return( hrRet );
  42. }
  43. /////////////////////////////////////////////////////////////////////////////
  44. // DllRegisterServer - Adds entries to the system registry
  45. STDAPI DllRegisterServer(void)
  46. {
  47. TRACEFNHR( "DllRegisterServer" );
  48. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  49. // registers object, typelib and all interfaces in typelib
  50. hrRet = RegisterServer( );
  51. return( hrRet );
  52. }
  53. /////////////////////////////////////////////////////////////////////////////
  54. // DllUnregisterServer - Removes entries from the system registry
  55. STDAPI DllUnregisterServer(void)
  56. {
  57. TRACEFNHR( "DllUnregisterServer" );
  58. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  59. hrRet = UnregisterServer( );
  60. return( hrRet );
  61. }
  62. #else
  63. /////////////////////////////////////////////////////////////////////////////
  64. // Setup to use if we are a standalone app //////////////////////////////////
  65. /////////////////////////////////////////////////////////////////////////////
  66. #define RecRegId IDR_CNotifyClientApp
  67. class CRecallParse : public CCommandLineInfo {
  68. virtual void ParseParam( LPCTSTR lpszParam, BOOL bFlag, BOOL bLast );
  69. public:
  70. BOOL m_RegAction;
  71. CRecallParse( ) { m_RegAction = FALSE; };
  72. };
  73. void CRecallParse::ParseParam( LPCTSTR lpszParam, BOOL bFlag, BOOL bLast )
  74. {
  75. TRACEFN( "CRecallParse::ParseParam" );
  76. CString cmdLine = lpszParam;
  77. if( bFlag ) {
  78. if( cmdLine.Left( unregString.GetLength( ) ) == unregString ) {
  79. UnregisterServer( );
  80. m_RegAction = TRUE;
  81. } else if( cmdLine.Left( regString.GetLength( ) ) == regString ) {
  82. RegisterServer( );
  83. m_RegAction = TRUE;
  84. }
  85. }
  86. }
  87. #endif
  88. /////////////////////////////////////////////////////////////////////////////
  89. // RegisterServer - Adds entries to the system registry
  90. HRESULT RegisterServer(void)
  91. {
  92. TRACEFNHR( "RegisterServer" );
  93. try {
  94. //
  95. // Add the object entries
  96. //
  97. RecAffirmHr( _Module.RegisterServer( FALSE ) );
  98. //
  99. // Add server entries
  100. //
  101. RecAffirmHr( _Module.UpdateRegistryFromResource( RecRegId, TRUE ) );
  102. //
  103. // Set up access to be allowed by everyone (NULL DACL)
  104. // Appears we need some owner and group, so use the current one.
  105. //
  106. CSecurityDescriptor secDesc;
  107. PSECURITY_DESCRIPTOR pSDSelfRelative = 0;
  108. RecAffirmHr( secDesc.InitializeFromProcessToken( ) );
  109. DWORD secDescSize = 0;
  110. MakeSelfRelativeSD( secDesc, pSDSelfRelative, &secDescSize );
  111. pSDSelfRelative = (PSECURITY_DESCRIPTOR) new char[secDescSize];
  112. if( MakeSelfRelativeSD( secDesc, pSDSelfRelative, &secDescSize ) ) {
  113. CString keyName = TEXT( "AppID\\{D68BD5B2-D6AA-11d0-9EDA-00A02488FCDE}" );
  114. CRegKey regKey;
  115. regKey.Open( HKEY_CLASSES_ROOT, keyName, KEY_SET_VALUE );
  116. RegSetValueEx( regKey.m_hKey, TEXT( "LaunchPermission" ), 0, REG_BINARY, (LPBYTE)pSDSelfRelative, secDescSize );
  117. }
  118. } RecCatch( hrRet );
  119. return( hrRet );
  120. }
  121. /////////////////////////////////////////////////////////////////////////////
  122. // UnregisterServer - Removes entries from the system registry
  123. HRESULT UnregisterServer(void)
  124. {
  125. TRACEFNHR( "UnregisterServer" );
  126. try {
  127. RecAffirmHr( _Module.UnregisterServer() );
  128. //
  129. // Remove server entries
  130. //
  131. RecAffirmHr( _Module.UpdateRegistryFromResource( RecRegId, FALSE ) );
  132. } RecCatch( hrRet );
  133. return( hrRet );
  134. }
  135. /////////////////////////////////////////////////////////////////////////////
  136. // CRecallApp
  137. BEGIN_MESSAGE_MAP(CRecallApp, CWinApp)
  138. //{{AFX_MSG_MAP(CRecallApp)
  139. // NOTE - the ClassWizard will add and remove mapping macros here.
  140. // DO NOT EDIT what you see in these blocks of generated code!
  141. //}}AFX_MSG
  142. END_MESSAGE_MAP()
  143. /////////////////////////////////////////////////////////////////////////////
  144. // CRecallApp construction
  145. CRecallApp::CRecallApp()
  146. {
  147. TRACEFN( "CRecallApp::CRecallApp" );
  148. m_IdleCount = 0;
  149. }
  150. /////////////////////////////////////////////////////////////////////////////
  151. // The one and only CRecallApp object
  152. CRecallApp theApp;
  153. /////////////////////////////////////////////////////////////////////////////
  154. // CRecallApp initialization
  155. BOOL CRecallApp::InitInstance()
  156. {
  157. TRACEFNHR( "CRecallApp::InitInstance" );
  158. LPTSTR cmdLine = GetCommandLine( );
  159. TRACE( cmdLine );
  160. try {
  161. _Module.Init( ObjectMap, m_hInstance );
  162. m_dwMaxConcurrentNotes = MAX_CONCURRENT_RECALL_NOTES_DEFAULT;
  163. InitCommonControls();
  164. #ifndef _USRDLL
  165. //
  166. // Initialize the COM module (no point to continue if it fails)
  167. //
  168. hrRet = CoInitialize( 0 );
  169. if (!SUCCEEDED(hrRet)) {
  170. return FALSE;
  171. }
  172. //
  173. // Parse the command line
  174. //
  175. CRecallParse parse;
  176. ParseCommandLine( parse );
  177. if( parse.m_RegAction ) {
  178. return FALSE;
  179. }
  180. //
  181. // This provides a NULL DACL which will allow access to everyone.
  182. //
  183. RecAffirmHr( CoInitializeSecurity( 0, -1, 0, 0, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, 0, EOAC_NONE, 0 ) );
  184. //
  185. // Register the Fsa callback object
  186. //
  187. RecAffirmHr( _Module.RegisterClassObjects( CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE ) );
  188. #endif
  189. // m_Wnd.Create( 0, TEXT( "Remote Storage Recall Notification Wnd" ) );
  190. // m_pMainWnd = &m_Wnd;
  191. CRecallWnd *pWnd = new CRecallWnd; // will auto delete
  192. RecAffirmPointer( pWnd );
  193. pWnd->Create( 0, TEXT( "Remote Storage Recall Notification Wnd" ) );
  194. m_pMainWnd = pWnd;
  195. // Check to see if there is any custom setting in the Registry for max recall popups
  196. // (ignore errors - just use default)
  197. HKEY hRegKey;
  198. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RSNTFY_REGISTRY_STRING, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) {
  199. DWORD dwType, dwValue;
  200. DWORD cbData = sizeof(DWORD);
  201. if (RegQueryValueEx(hRegKey, MAX_CONCURRENT_RECALL_NOTES, 0, &dwType, (BYTE*)&dwValue, &cbData) == ERROR_SUCCESS) {
  202. if (REG_DWORD == dwType) {
  203. // custom setting
  204. m_dwMaxConcurrentNotes = dwValue;
  205. }
  206. }
  207. RegCloseKey(hRegKey);
  208. }
  209. } RecCatch( hrRet );
  210. return TRUE;
  211. }
  212. int CRecallApp::ExitInstance()
  213. {
  214. TRACEFN("CRecallApp::ExitInstance");
  215. _Module.Term();
  216. #ifndef _USRDLL
  217. CoUninitialize();
  218. #endif
  219. return CWinApp::ExitInstance();
  220. }
  221. void CRecallApp::LockApp( )
  222. {
  223. TRACEFNLONG( "CRecallApp::LockApp" );
  224. lRet = _Module.Lock( );
  225. }
  226. void CRecallApp::UnlockApp( )
  227. {
  228. TRACEFNLONG( "CRecallApp::UnlockApp" );
  229. lRet = _Module.Unlock( );
  230. // Don't call AfxPostQuitMessage when ref. count drops to zero
  231. // The timer mechanism is responsible for terminating this application.
  232. // Also, when the ref count drops to zero, COM terminates the process after some time.
  233. }
  234. HRESULT CRecallApp::AddRecall( IFsaRecallNotifyServer* pRecall )
  235. {
  236. TRACEFNHR( "CRecallApp::AddRecall" );
  237. CRecallNote * pNote = 0;
  238. try {
  239. //
  240. // Create a new note to show - only if we didn't pass the max number for concurrent notes
  241. // Note: We return S_OK and not S_FALSE even if the recall popup is not displayed in order
  242. // not to break the server (S_FALSE will cause unnecessary retries)
  243. //
  244. if (m_Recalls.GetCount() < (int)m_dwMaxConcurrentNotes) {
  245. pNote = new CRecallNote( pRecall, CWnd::GetDesktopWindow( ) );
  246. RecAffirmHr( pNote->m_hrCreate );
  247. m_Recalls.AddTail( pNote );
  248. } else {
  249. TRACE( _T("Recall not added - reached max number of recalls"));
  250. }
  251. } RecCatchAndDo( hrRet,
  252. if( 0 != pNote ) delete pNote;
  253. );
  254. return( hrRet );
  255. }
  256. //
  257. // Note:
  258. // No CS is used here because the RsNotify is initialized as a single threaded application
  259. //
  260. HRESULT CRecallApp::RemoveRecall( IFsaRecallNotifyServer* pRecall )
  261. {
  262. TRACEFNHR( "CRecallApp::RemoveRecall" );
  263. hrRet = S_FALSE;
  264. if( ( m_Recalls.IsEmpty() ) ) {
  265. return( hrRet );
  266. }
  267. CRecallNote* pNote = 0;
  268. POSITION pos = m_Recalls.GetHeadPosition( );
  269. POSITION currentPos = 0;
  270. //
  271. // Look through the list and find this one
  272. //
  273. GUID recallId;
  274. pRecall->GetIdentifier( &recallId );
  275. while( pos != 0 ) {
  276. currentPos = pos;
  277. pNote = m_Recalls.GetNext( pos );
  278. if( IsEqualGUID( recallId, pNote->m_RecallId ) ) {
  279. if (pNote->m_bCancelled) {
  280. //
  281. // This means that somebody is already removing this recall
  282. // The Remove may be called up to 3 times for the same recall in case
  283. // of a recall cancellation
  284. //
  285. hrRet = S_OK;
  286. pos = 0; // exit loop
  287. } else {
  288. pNote->m_bCancelled = TRUE;
  289. //
  290. // Remove and delete. Return OK.
  291. //
  292. m_Recalls.RemoveAt( currentPos );
  293. pNote->DestroyWindow( );
  294. pos = 0; // exit loop
  295. hrRet = S_OK;
  296. }
  297. }
  298. }
  299. return( hrRet );
  300. }
  301. // CRecallApp::Tick - called every second (after an initial delay
  302. // for startup) to keep track of idle time
  303. void CRecallApp::Tick( )
  304. {
  305. TRACEFN( "CRecallApp::Tick");
  306. // Check for pending recalls
  307. if( m_Recalls.GetCount( ) ) {
  308. // We have pending recalls, reset the idle count
  309. TRACE( _T("m_Recalls.GetCount != 0") );
  310. m_IdleCount = 0;
  311. } else {
  312. // We don't have pending recalls, increment the idle count
  313. TRACE( _T("m_Recalls.GetCount == 0") );
  314. m_IdleCount++;
  315. if( m_IdleCount > RSRECALL_TIME_MAX_IDLE ) {
  316. TRACE( _T("m_IdleCount > 0") );
  317. // Nothing's happin', say "Goodbye"
  318. m_pMainWnd->PostMessage( WM_CLOSE );
  319. TRACE( _T("after PostMessage(WM_CLOSE)") );
  320. }
  321. }
  322. }
  323. /////////////////////////////////////////////////////////////////////////////
  324. // CRecallWnd
  325. CRecallWnd::CRecallWnd()
  326. {
  327. TRACEFN( "CRecallWnd::CRecallWnd" );
  328. }
  329. CRecallWnd::~CRecallWnd()
  330. {
  331. TRACEFN( "CRecallWnd::~CRecallWnd" );
  332. }
  333. BEGIN_MESSAGE_MAP(CRecallWnd, CWnd)
  334. //{{AFX_MSG_MAP(CRecallWnd)
  335. ON_WM_TIMER()
  336. ON_WM_CREATE()
  337. //}}AFX_MSG_MAP
  338. END_MESSAGE_MAP()
  339. /////////////////////////////////////////////////////////////////////////////
  340. // CRecallWnd message handlers
  341. void CRecallWnd::OnTimer(UINT nIDEvent)
  342. {
  343. TRACEFN("CRecallWnd::OnTimer");
  344. if (1 == nIDEvent) {
  345. // Initial timer. Kill it and start one for every second
  346. TRACE( _T("nIDEvent == 1") );
  347. KillTimer( nIDEvent );
  348. SetTimer( 2, 1000, NULL );
  349. } else {
  350. // One second timer. Notify the app object
  351. RecApp->Tick();
  352. }
  353. CWnd::OnTimer( nIDEvent );
  354. }
  355. int CRecallWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
  356. {
  357. TRACEFN("CRecallWnd::OnCreate" );
  358. if (CWnd::OnCreate(lpCreateStruct) == -1)
  359. return -1;
  360. // Set the initial timer to allow time for startup
  361. if (!SetTimer(1, RSRECALL_TIME_FOR_STARTUP * 1000, NULL))
  362. return -1;
  363. return 0;
  364. }