sdmain.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 30k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. #ifdef POSTSPLIT
  4. #include "cmnquery.h"
  5. #include "dsquery.h"
  6. #include "startids.h"
  7. #include "dsgetdc.h"
  8. #include "lm.h"
  9. #include "wab.h"
  10. #include "winldap.h"
  11. #include "activeds.h"
  12. // This is the implementation for the Shell Application level IDispatch
  13. // Currently we will try to maintain only one object per process.
  14. // BUGBUG:: The following defines must be equal to the stuff in cabinet.h...
  15. #define IDM_SYSBUTTON   300
  16. #define IDM_FINDBUTTON  301
  17. #define IDM_HELPBUTTON  302
  18. #define IDM_FILERUN                 401
  19. #define IDM_CASCADE                 403
  20. #define IDM_HORIZTILE               404
  21. #define IDM_VERTTILE                405
  22. #define IDM_DESKTOPARRANGEGRID      406
  23. #define IDM_ARRANGEMINIMIZEDWINDOWS 407
  24. #define IDM_SETTIME                 408
  25. #define IDM_SUSPEND                 409
  26. #define IDM_EJECTPC                 410
  27. #define IDM_TASKLIST                412
  28. #define IDM_TRAYPROPERTIES          413
  29. #define IDM_EDITSTARTMENU           414
  30. #define IDM_MINIMIZEALL             415
  31. #define IDM_UNDO                    416
  32. #define IDM_RETURN                  417
  33. #define IDM_PRINTNOTIFY_FOLDER      418
  34. #define IDM_MINIMIZEALLHOTKEY       419
  35. #define IDM_SHOWTASKMAN             420
  36. #define IDM_RECENT              501
  37. #define IDM_FIND                502
  38. #define IDM_PROGRAMS            504
  39. #define IDM_CONTROLS            505
  40. #define IDM_EXITWIN             506
  41. // #define IDM_FONTS            509
  42. #define IDM_PRINTERS            510
  43. #define IDM_STARTMENU           511
  44. #define IDM_MYCOMPUTER          512
  45. #define IDM_PROGRAMSINIT        513
  46. #define IDM_RECENTINIT          514
  47. #define IDM_MENU_FIND           520
  48. #define TRAY_IDM_FINDFIRST      521  // this range
  49. #define TRAY_IDM_FINDLAST       550  // is reserved for find command
  50. #define IDM_RECENTLIST          650
  51. #define IDM_QUICKTIPS   800
  52. #define IDM_HELPCONT    801
  53. #define IDM_WIZARDS     802
  54. #define IDM_USEHELP     803             // REVIEW: probably won't be used
  55. #define IDM_TUTORIAL    804
  56. #define IDM_ABOUT       805
  57. #define IDM_LAST_MENU_ITEM   IDM_ABOUT
  58. #define FCIDM_FIRST             FCIDM_GLOBALFIRST
  59. #define FCIDM_LAST              FCIDM_BROWSERLAST
  60. //#define FCIDM_FINDFILES         (FCIDM_BROWSER_TOOLS+0x0005)
  61. #define FCIDM_FINDCOMPUTER      (FCIDM_BROWSER_TOOLS+0x0006)
  62. //============================================================================
  63. class CShellDispatch : public IShellDispatch2, 
  64.                        public CObjectSafety,
  65.                        protected CImpIDispatch,
  66.                        public CObjectWithSite
  67. {
  68.    friend class CAdviseRouter;
  69.    friend HRESULT GetApplicationObject(DWORD dwSafetyOptions, IUnknown *punkSite, IDispatch **ppid);
  70.     public:
  71.         //Non-delegating object IUnknown
  72.         STDMETHODIMP         QueryInterface(REFIID, void **);
  73.         STDMETHODIMP_(ULONG) AddRef(void);
  74.         STDMETHODIMP_(ULONG) Release(void);
  75.         //IDispatch members
  76.         virtual STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
  77.             { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  78.         virtual STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  79.             { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  80.         virtual STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
  81.             { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  82.         virtual STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  83.             { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
  84.         //IShellDispatch functions
  85.         STDMETHODIMP get_Application(IDispatch **ppid);
  86.         STDMETHODIMP get_Parent (IDispatch **ppid);
  87.         STDMETHOD(Open)(THIS_ VARIANT vDir);
  88.         STDMETHOD(Explore)(THIS_ VARIANT vDir);
  89.         STDMETHOD(NameSpace)(THIS_ VARIANT vDir, Folder **ppsdf);
  90.         STDMETHODIMP BrowseForFolder(long Hwnd, BSTR Title, long Options, VARIANT RootFolder, Folder **ppsdf);
  91.         STDMETHODIMP ControlPanelItem(BSTR szDir);
  92.         STDMETHODIMP MinimizeAll(void);
  93.         STDMETHODIMP UndoMinimizeALL(void);
  94.         STDMETHODIMP FileRun(void);
  95.         STDMETHODIMP CascadeWindows(void);
  96.         STDMETHODIMP TileVertically(void);
  97.         STDMETHODIMP TileHorizontally(void);
  98.         STDMETHODIMP ShutdownWindows(void);
  99.         STDMETHODIMP Suspend(void);
  100.         STDMETHODIMP EjectPC(void);
  101.         STDMETHODIMP SetTime(void);
  102.         STDMETHODIMP TrayProperties(void);
  103.         STDMETHODIMP Help(void);
  104.         STDMETHODIMP FindFiles(void);
  105.         STDMETHODIMP FindComputer(void);
  106.         STDMETHODIMP RefreshMenu(void);
  107.         STDMETHODIMP Windows(IDispatch **ppid);
  108.         STDMETHODIMP get_ObjectCount(int *pcObjs);
  109.         STDMETHODIMP IsRestricted(BSTR Group, BSTR Restriction, long * lpValue);
  110.         STDMETHODIMP ShellExecute(BSTR File, VARIANT vArgs, VARIANT vDir, VARIANT vOperation, VARIANT vShow);
  111.         STDMETHODIMP FindPrinter(BSTR name, BSTR location, BSTR model);
  112.         STDMETHODIMP GetSystemInformation(BSTR name, VARIANT * pvOut);
  113.         STDMETHODIMP ServiceStart(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess);
  114.         STDMETHODIMP ServiceStop(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess);
  115.         STDMETHODIMP IsServiceRunning(BSTR ServiceName, VARIANT *pRunning);
  116.         STDMETHODIMP CanStartStopService(BSTR ServiceName, VARIANT *pCanStartStop);
  117.         STDMETHODIMP ShowBrowserBar( BSTR bstrClsid, VARIANT bShow, VARIANT *pSuccess );
  118.                 
  119.         // Constructor and the like.. 
  120.         CShellDispatch(void);
  121.     protected:
  122.         ULONG           m_cRef;             //Object reference count
  123.     
  124.         ~CShellDispatch(void);
  125.         BOOL            FAllowUserToDoAnything(void);   // Check if we are in paranoid mode...
  126.         HRESULT         _TrayCommand(UINT idCmd);
  127.         HRESULT         ExecuteFolder(VARIANT vDir, LPCTSTR pszVerb);
  128.         VARIANT_BOOL    _ServiceStartStop(BSTR ServiceName, BOOL fStart, BOOL fPersist);
  129.         HMODULE         m_hmodWAB;          // module handle for WAB32 
  130.         LPWABOPEN       _GetWABOpen();
  131.         HRESULT         _GetNC(BSTR *pbstrResult, LPCTSTR pszDnsForestName);
  132. };
  133. STDAPI CShellDispatch_CreateInstance(IUnknown* pUnkOuter, REFIID riid, void **ppvOut)
  134. {
  135.     HRESULT hr = E_OUTOFMEMORY;
  136.     *ppvOut = NULL;
  137.     TraceMsg(DM_TRACE, "CSD_CreateInstance called");
  138.     // aggregation checking is handled in class factory
  139.     CShellDispatch * pshd = new CShellDispatch();
  140.     if (pshd)
  141.     {
  142.         hr = pshd->QueryInterface(riid, ppvOut);
  143.         pshd->Release();   // g_pCShellDispatch doesn't want a ref.
  144.     }
  145.     return hr;
  146. }
  147. HRESULT GetApplicationObject(DWORD dwSafetyOptions, IUnknown *punkSite, IDispatch **ppid)
  148. {
  149.     *ppid = NULL;   // Handle failure cases.
  150.     if (dwSafetyOptions && (!punkSite || IsSafePage(punkSite) != S_OK))
  151.         return E_ACCESSDENIED;
  152.     HRESULT hres = CShellDispatch_CreateInstance(NULL, IID_IDispatch, (void **) ppid);
  153.     if (SUCCEEDED(hres))
  154.     {
  155.         if (punkSite)
  156.             IUnknown_SetSite(*ppid, punkSite);
  157.         if (dwSafetyOptions && SUCCEEDED(hres))
  158.             hres = MakeSafeForScripting((IUnknown**)ppid);
  159.     }
  160.     return hres;
  161. }
  162. CShellDispatch::CShellDispatch(void) :
  163.         m_cRef(1), 
  164.         m_hmodWAB(NULL),
  165.         CImpIDispatch(&LIBID_Shell32, 1, 0, &IID_IShellDispatch2)
  166. {
  167.     DllAddRef();
  168.     TraceMsg(DM_TRACE, "CShellDispatch::CShellDispatch called");
  169. }
  170. CShellDispatch::~CShellDispatch(void)
  171. {
  172.     TraceMsg(DM_TRACE, "CShellDispatch::~CShellDispatch called");
  173.     
  174.     if ( m_hmodWAB )
  175.         FreeLibrary(m_hmodWAB);
  176.     DllRelease();
  177. }
  178. BOOL  CShellDispatch::FAllowUserToDoAnything(void)
  179. {
  180.     if (!_dwSafetyOptions)
  181.         return TRUE;   // We are not running in safe mode so say everything is OK...   
  182.     if (!_punkSite)
  183.         return FALSE;   // We are in safe but don't have anyway to know where we are...
  184.     return (IsSafePage(_punkSite) == S_OK);
  185. }
  186. STDMETHODIMP CShellDispatch::QueryInterface(REFIID riid, void ** ppv)
  187. {
  188.     TraceMsg(DM_TRACE, "CShellDispatch::QueryInterface called");
  189.     static const QITAB qit[] = {
  190.         QITABENT(CShellDispatch, IShellDispatch2),
  191.         QITABENTMULTI(CShellDispatch, IShellDispatch, IShellDispatch2),
  192.         QITABENTMULTI(CShellDispatch, IDispatch, IShellDispatch2),
  193.         QITABENT(CShellDispatch, IObjectSafety),
  194.         QITABENT(CShellDispatch, IObjectWithSite),
  195.         { 0 },
  196.     };
  197.     return QISearch(this, qit, riid, ppv);
  198. }
  199. STDMETHODIMP_(ULONG) CShellDispatch::AddRef(void)
  200. {
  201.     TraceMsg(DM_TRACE, "CShellDispatch::AddRef called");
  202.     return ++m_cRef;
  203. }
  204. STDMETHODIMP_(ULONG) CShellDispatch::Release(void)
  205. {
  206.     TraceMsg(DM_TRACE, "CShellDispatch::Release called");
  207.     if (0L!=--m_cRef)
  208.         return m_cRef;
  209.     delete this;
  210.     return 0L;
  211. }
  212. // Helper function to process commands to the tray.
  213. HRESULT CShellDispatch::_TrayCommand(UINT idCmd)
  214. {
  215.     if (!FAllowUserToDoAnything())
  216.         return E_ACCESSDENIED;
  217.     HWND hwndTray = FindWindowA(WNDCLASS_TRAYNOTIFY, NULL);
  218.     if (hwndTray)
  219.         PostMessage(hwndTray, WM_COMMAND, idCmd, 0);
  220.     return NOERROR;
  221. }
  222. STDMETHODIMP CShellDispatch::get_Application(IDispatch **ppid)
  223. {
  224.     // Simply return ourself
  225.     return QueryInterface(IID_IDispatch, (PVOID*)ppid);
  226. }
  227. STDMETHODIMP CShellDispatch::get_Parent(IDispatch **ppid)
  228. {
  229.     return QueryInterface(IID_IDispatch, (PVOID*)ppid);
  230. }
  231. HRESULT CShellDispatch::ExecuteFolder(VARIANT vDir, LPCTSTR pszVerb)
  232. {
  233.     SHELLEXECUTEINFO sei = {sizeof(SHELLEXECUTEINFO)};  
  234.     // Check to see if we allow the user to do this...
  235.     if (!FAllowUserToDoAnything())
  236.         return E_ACCESSDENIED;
  237.     sei.lpIDList = (void *)VariantToIDList(&vDir);
  238.     if (sei.lpIDList)
  239.     {
  240.         // Everything should have been initialize to 0
  241.         // BUGBUG:: Should be invoke idlist but that is failing when
  242.         // explore
  243.         sei.fMask = SEE_MASK_IDLIST;
  244.         sei.nShow = SW_SHOWNORMAL;
  245.         sei.lpVerb = pszVerb;
  246.         //TraceMsg(DM_TRACE, "CShellDispatch::Open(%s) called", szParam);
  247.         HRESULT hres = ShellExecuteEx(&sei) ? NOERROR : S_FALSE;
  248.         ILFree((LPITEMIDLIST)sei.lpIDList);
  249.         return hres;
  250.     }
  251.     return S_FALSE; // bad dir
  252. }
  253. STDMETHODIMP CShellDispatch::Open(VARIANT vDir)
  254. {
  255.     return ExecuteFolder(vDir, NULL);
  256. }
  257. STDMETHODIMP CShellDispatch::Explore(VARIANT vDir)
  258. {
  259.     return ExecuteFolder(vDir, TEXT("explore"));
  260. }
  261. STDMETHODIMP CShellDispatch::NameSpace(VARIANT vDir, Folder **ppsdf)
  262. {
  263.     *ppsdf = NULL;
  264.     if (!FAllowUserToDoAnything())
  265.         return E_ACCESSDENIED;
  266.     HRESULT hres;
  267.     LPITEMIDLIST pidl = VariantToIDList(&vDir);
  268.     if (pidl)
  269.     {
  270.         hres = CFolder_Create(NULL, pidl, NULL, IID_Folder, (void **)ppsdf);
  271.         ILFree(pidl);
  272.     }
  273.     else
  274.         hres = S_FALSE; // bad dir
  275.     return hres;
  276. }
  277. STDMETHODIMP CShellDispatch::IsRestricted(BSTR Group, BSTR Restriction, long * lpValue)
  278. {
  279.     if (lpValue) 
  280.         *lpValue = SHGetRestriction(NULL, Group, Restriction);
  281.     return S_OK;
  282. }
  283. STDMETHODIMP CShellDispatch::ShellExecute(BSTR File, VARIANT vArgs, VARIANT vDir, VARIANT vOperation, VARIANT vShow)
  284. {
  285.     SHELLEXECUTEINFO sei = {sizeof(SHELLEXECUTEINFO)};  
  286.     TCHAR szFile[MAX_PATH];
  287.     TCHAR szDir[MAX_PATH];
  288.     TCHAR szOper[128];  // don't think any verb longer than this...
  289.     // Check to see if we allow the user to do this...
  290.     if (!FAllowUserToDoAnything())
  291.         return E_ACCESSDENIED;
  292.     // Initialize the shellexecute structure...
  293.     sei.nShow = SW_SHOWNORMAL;
  294.     // Ok setup the FileName.
  295.     SHUnicodeToTCharCP(CP_ACP, File, szFile, ARRAYSIZE(szFile));
  296.     sei.lpFile = szFile;
  297.     // Now the Args
  298.     sei.lpParameters = VariantToStr(&vArgs, NULL, 0);
  299.     sei.lpDirectory = VariantToStr(&vDir, szDir, ARRAYSIZE(szDir));
  300.     sei.lpVerb = VariantToStr(&vOperation, szOper, ARRAYSIZE(szOper));
  301.     // Finally the show -- Could use convert, but that takes 3 calls...
  302.     if (vShow.vt == (VT_BYREF|VT_VARIANT) && vShow.pvarVal)
  303.         vShow = *vShow.pvarVal;
  304.     switch (vShow.vt)
  305.     {
  306.     case VT_I2:
  307.         sei.nShow = (int)vShow.iVal;
  308.         break;
  309.     case VT_I4:
  310.         sei.nShow = (int)vShow.lVal;
  311.     }
  312.     HRESULT hres = ShellExecuteEx(&sei) ? NOERROR : S_FALSE;
  313.     // Cleanup anything we allocated
  314.     if (sei.lpParameters)
  315.         LocalFree((HLOCAL)sei.lpParameters);
  316.     return hres;
  317. }
  318. //
  319. // These next few methods deal with NT services in general, and the
  320. // Content Indexing Service in particular, so they're stubbed out
  321. // to return E_NOTIMPL on Win9x.
  322. //
  323. //
  324. // Helper function for ServiceStart and ServiceStop
  325. //
  326. VARIANT_BOOL CShellDispatch::_ServiceStartStop(BSTR ServiceName, BOOL fStart, BOOL fPersistent)
  327. {
  328. #ifdef WINNT
  329.     SC_HANDLE hSvc = 0;
  330.     SC_HANDLE hSc = 0;
  331.     BOOL fResult = FALSE;
  332.     VARIANT_BOOL fRetVal = VARIANT_FALSE;
  333.     SERVICE_STATUS ServiceStatus;
  334.     hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  335.     if (!hSc) {
  336.         goto exit_gracefully;
  337.     } // if
  338.     hSvc = OpenServiceW(
  339.         hSc,
  340.         ServiceName,
  341.         (fStart ? SERVICE_START : SERVICE_STOP) 
  342.             | (fPersistent ? SERVICE_CHANGE_CONFIG : 0)
  343.     );
  344.     if (!hSvc) {
  345.         goto exit_gracefully;
  346.     } // if
  347.         
  348.     if (fPersistent) {
  349.         fResult = ChangeServiceConfig(
  350.             hSvc,
  351.             SERVICE_NO_CHANGE,
  352.             (fStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START),
  353.             SERVICE_NO_CHANGE,
  354.             NULL,
  355.             NULL,
  356.             NULL,
  357.             NULL,
  358.             NULL,
  359.             NULL,
  360.             NULL
  361.         );
  362.         
  363.         //
  364.         // Consider failure here a soft error.
  365.         //
  366.     } // if (fPersistent)
  367.     if (fStart) {
  368.         fResult = StartService(hSvc, 0, NULL);
  369.     }
  370.     else {
  371.         fResult = ControlService(hSvc, SERVICE_CONTROL_STOP, &ServiceStatus);
  372.     }
  373.     if (!fResult) {
  374.         goto exit_gracefully;
  375.     } // if
  376.     fRetVal = VARIANT_TRUE;
  377. exit_gracefully:
  378.     if (hSvc) {
  379.         CloseServiceHandle(hSvc);
  380.         hSvc = 0;
  381.     } // if
  382.     if (hSc) {
  383.         CloseServiceHandle(hSc);
  384.         hSc = 0;
  385.     } // if
  386.     return(fRetVal);
  387. #else // WINNT
  388.     return(FALSE);
  389. #endif // WINNT
  390. }
  391. STDMETHODIMP CShellDispatch::ServiceStart(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess)
  392. {
  393. #ifdef WINNT
  394.     // Check to see if we allow the user to do this...
  395.     if (!FAllowUserToDoAnything())
  396.         return E_ACCESSDENIED;
  397.     if (VT_BOOL != Persistent.vt) {
  398.         return(E_INVALIDARG);
  399.     } // if
  400.     VariantClear(pSuccess);
  401.     pSuccess->vt = VT_BOOL;
  402.     pSuccess->boolVal = _ServiceStartStop(ServiceName, TRUE, Persistent.boolVal);
  403.     return(S_OK);
  404. #else // WINNT
  405.     return(E_NOTIMPL);
  406. #endif // WINNT
  407. }
  408. STDMETHODIMP CShellDispatch::ServiceStop(BSTR ServiceName, VARIANT Persistent, VARIANT *pSuccess)
  409. {
  410. #ifdef WINNT
  411.     // Check to see if we allow the user to do this...
  412.     if (!FAllowUserToDoAnything())
  413.         return E_ACCESSDENIED;
  414.     if (VT_BOOL != Persistent.vt) {
  415.         return(E_INVALIDARG);
  416.     } // if
  417.     VariantClear(pSuccess);
  418.     pSuccess->vt = VT_BOOL;
  419.     pSuccess->boolVal = _ServiceStartStop(ServiceName, FALSE, Persistent.boolVal);
  420.     return(S_OK);
  421. #else // WINNT
  422.     return(E_NOTIMPL);
  423. #endif // WINNT
  424. }
  425. STDMETHODIMP CShellDispatch::IsServiceRunning(BSTR ServiceName, VARIANT *pIsRunning)
  426. {
  427. #ifdef WINNT
  428.     SC_HANDLE hSvc = 0;
  429.     SC_HANDLE hSc = 0;
  430.     SERVICE_STATUS ServiceStatus;
  431.     BOOL fResult = FALSE;
  432.     VariantClear(pIsRunning);
  433.     pIsRunning->vt = VT_BOOL;
  434.     pIsRunning->boolVal = VARIANT_FALSE;
  435.     // Check to see if we allow the user to do this...
  436.     if (!FAllowUserToDoAnything())
  437.         return E_ACCESSDENIED;
  438.     hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  439.     if (!hSc) {
  440.         goto exit_gracefully;
  441.     } // if
  442.     hSvc = OpenService(
  443.         hSc,
  444.         ServiceName,
  445.         SERVICE_QUERY_STATUS
  446.     );
  447.     if (!hSvc) {
  448.         goto exit_gracefully;
  449.     } // if
  450.         
  451.     fResult = QueryServiceStatus(hSvc, &ServiceStatus);
  452.     if (!fResult) {
  453.         goto exit_gracefully;
  454.     } // if
  455.     switch (ServiceStatus.dwCurrentState) {
  456.         case SERVICE_START_PENDING:
  457.         case SERVICE_RUNNING:
  458.         case SERVICE_CONTINUE_PENDING:
  459.             pIsRunning->boolVal = VARIANT_TRUE;
  460.             break;
  461.         default:
  462.             break;
  463.     } // switch
  464. exit_gracefully:
  465.     if (hSc) {
  466.         CloseServiceHandle(hSc);
  467.         hSc = 0;
  468.     } // if
  469.     if (hSvc) {
  470.         CloseServiceHandle(hSvc);
  471.         hSvc = 0;
  472.     } // if
  473.     return(S_OK);
  474. #else // WINNT
  475.     return(E_NOTIMPL);
  476. #endif
  477. }
  478. STDMETHODIMP CShellDispatch::CanStartStopService(BSTR ServiceName, VARIANT *pCanStartStop)
  479. {
  480. #ifdef WINNT
  481.     SC_HANDLE hSvc = 0;
  482.     SC_HANDLE hSc = 0;
  483.     BOOL fResult = FALSE;
  484.     VariantClear(pCanStartStop);
  485.     pCanStartStop->vt = VT_BOOL;
  486.     pCanStartStop->boolVal = VARIANT_FALSE;
  487.     // Check to see if we allow the user to do this...
  488.     if (!FAllowUserToDoAnything())
  489.         return E_ACCESSDENIED;
  490.     hSc = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  491.     if (!hSc) {
  492.         goto exit_gracefully;
  493.     } // if
  494.     hSvc = OpenService(
  495.         hSc,
  496.         ServiceName,
  497.         SERVICE_START | SERVICE_STOP | SERVICE_CHANGE_CONFIG
  498.     );
  499.     if (!hSvc) {
  500.         DWORD dwErr = GetLastError() ;
  501.         goto exit_gracefully;
  502.     } // if
  503.         
  504.     pCanStartStop->boolVal = VARIANT_TRUE;
  505. exit_gracefully:
  506.     if (hSc) {
  507.         CloseServiceHandle(hSc);
  508.         hSc = 0;
  509.     } // if
  510.     if (hSvc) {
  511.         CloseServiceHandle(hSvc);
  512.         hSvc = 0;
  513.     } // if
  514.     return(S_OK);
  515. #else // WINNT
  516.     return(E_NOTIMPL);
  517. #endif // WINNT
  518. }
  519. STDMETHODIMP CShellDispatch::ShowBrowserBar(BSTR bstrClsid, VARIANT varShow, VARIANT *pSuccess)
  520. {
  521.     if( !(bstrClsid && *bstrClsid && pSuccess) )
  522.         return E_INVALIDARG ;
  523.     HRESULT hr        = E_FAIL ;
  524.     pSuccess->vt      = VT_BOOL ;
  525.     pSuccess->boolVal = VARIANT_FALSE ;
  526.     if( NULL == _punkSite )
  527.         return E_FAIL ;
  528.     IShellBrowser* psb ;
  529.     hr = IUnknown_QueryService( _punkSite, SID_STopLevelBrowser, IID_IShellBrowser, (void **)&psb ) ;
  530.     if( SUCCEEDED( hr ) ) 
  531.     {
  532.         IWebBrowser2 *pb2;
  533.         hr = IUnknown_QueryService( psb, SID_SWebBrowserApp, IID_IWebBrowser2, 
  534.                                    (void **)&pb2);
  535.         if (SUCCEEDED(hr))
  536.         {
  537.             VARIANT varGuid, varNil ;
  538.         
  539.             varGuid.vt      = VT_BSTR ;
  540.             varGuid.bstrVal = bstrClsid ;
  541.             VariantInit( &varNil ) ;
  542.             hr = pb2->ShowBrowserBar( &varGuid, &varShow, &varNil ) ;
  543.             
  544.             if( SUCCEEDED( hr ) )
  545.                 pSuccess->boolVal = VARIANT_TRUE ;
  546.         
  547.             pb2->Release() ;
  548.         }
  549.         psb->Release() ;
  550.     }
  551.     return hr ;
  552. }
  553. STDMETHODIMP CShellDispatch::BrowseForFolder(long Hwnd, BSTR Title, long Options, 
  554.         VARIANT RootFolder, Folder **ppsdf)
  555. {
  556.     // BUGBUG:: Not all of the arguments are being processed yet...
  557.     TCHAR szTitle[MAX_PATH];      // hopefully long enough...
  558.     BROWSEINFO browse;
  559.     LPITEMIDLIST pidl;
  560.     HRESULT hres;
  561.     if (!FAllowUserToDoAnything())
  562.         return E_ACCESSDENIED;
  563.     SHUnicodeToTCharCP(CP_ACP, Title, szTitle, ARRAYSIZE(szTitle));
  564.     browse.lpszTitle = szTitle;
  565.     browse.pszDisplayName = NULL;
  566.     browse.hwndOwner = (HWND)LongToHandle( Hwnd );
  567.     browse.ulFlags = (ULONG)Options;
  568.     browse.lpfn = NULL;
  569.     browse.lParam = 0;
  570.     browse.iImage = 0;
  571.     browse.pidlRoot = VariantToIDList(&RootFolder);
  572.     pidl = SHBrowseForFolder(&browse);
  573.     if (browse.pidlRoot)
  574.         ILFree((LPITEMIDLIST)browse.pidlRoot);
  575.     *ppsdf = NULL;
  576.     if (pidl)
  577.     {
  578.         hres = CFolder_Create(NULL, pidl, NULL, IID_Folder, (void **)ppsdf);
  579.         ILFree(pidl);
  580.     }
  581.     else
  582.         hres = S_FALSE;     // Not a strong error...
  583.     return hres;
  584. }
  585. STDMETHODIMP CShellDispatch::ControlPanelItem(BSTR bszDir)
  586. {
  587.     if (!FAllowUserToDoAnything())
  588.         return E_ACCESSDENIED;
  589. #ifdef UNICODE
  590.     SHRunControlPanel(bszDir, NULL);
  591. #else // UNICODE
  592.     TCHAR szParam[MAX_PATH];
  593.     SHUnicodeToAnsi(bszDir, szParam, ARRAYSIZE(szParam));
  594.     SHRunControlPanel(szParam, NULL);
  595.     TraceMsg(DM_TRACE, "CShellDispatch::ControlPanelItem(%s) called", szParam);
  596. #endif // UNICODE
  597.     return NOERROR;
  598. }
  599. STDMETHODIMP CShellDispatch::MinimizeAll(void)
  600. {
  601.     return _TrayCommand(IDM_MINIMIZEALL);
  602. }
  603. STDMETHODIMP CShellDispatch::UndoMinimizeALL(void)
  604. {
  605.     return _TrayCommand(IDM_UNDO);
  606. }
  607. STDMETHODIMP CShellDispatch::FileRun(void)
  608. {
  609.     return _TrayCommand(IDM_FILERUN);
  610. }
  611. STDMETHODIMP CShellDispatch::CascadeWindows(void)
  612. {
  613.     return _TrayCommand(IDM_CASCADE);
  614. }
  615. STDMETHODIMP CShellDispatch::TileVertically(void)
  616. {
  617.     return _TrayCommand(IDM_VERTTILE);
  618. }
  619. STDMETHODIMP CShellDispatch::TileHorizontally(void)
  620. {
  621.     return _TrayCommand(IDM_HORIZTILE);
  622. }
  623. STDMETHODIMP CShellDispatch::ShutdownWindows(void)
  624. {
  625.     return _TrayCommand(IDM_EXITWIN);
  626. }
  627. STDMETHODIMP CShellDispatch::Suspend(void)
  628. {
  629.     return _TrayCommand(IDM_SUSPEND);
  630. }
  631. STDMETHODIMP CShellDispatch::EjectPC(void)
  632. {
  633.     return _TrayCommand(IDM_EJECTPC);
  634. }
  635. STDMETHODIMP CShellDispatch::SetTime(void)
  636. {
  637.     return _TrayCommand(IDM_SETTIME);
  638. }
  639. STDMETHODIMP CShellDispatch::TrayProperties(void)
  640. {
  641.     return _TrayCommand(IDM_TRAYPROPERTIES);
  642. }
  643. STDMETHODIMP CShellDispatch::Help(void)
  644. {
  645.     return _TrayCommand(IDM_HELPSEARCH);
  646. }
  647. STDMETHODIMP CShellDispatch::FindFiles(void)
  648. {
  649.     return _TrayCommand(FCIDM_FINDFILES);
  650. }
  651. STDMETHODIMP CShellDispatch::FindComputer(void)
  652. {
  653.     return _TrayCommand(FCIDM_FINDCOMPUTER);
  654. }
  655. STDMETHODIMP CShellDispatch::RefreshMenu(void)
  656. {
  657.     return _TrayCommand(FCIDM_REFRESH);
  658. }
  659. STDMETHODIMP CShellDispatch::Windows(IDispatch **ppid)
  660. {
  661.     if (!FAllowUserToDoAnything())
  662.         return E_ACCESSDENIED;
  663.     return CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)ppid);
  664. }
  665. //
  666. // the "FindPrinter" method on the application object invokes the DS query to find a printer given
  667. // the name, location and model.  Because the query UI is a blocking API we spin this onto a seperate
  668. // thread before calling "OpenQueryWindow".
  669. //
  670. typedef struct 
  671. {
  672.     LPWSTR pszName;
  673.     LPWSTR pszLocation;
  674.     LPWSTR pszModel;
  675. } FINDPRINTERINFO;
  676. void _FreeFindPrinterInfo(FINDPRINTERINFO *pfpi)
  677. {
  678.     if ( pfpi )
  679.     {
  680.         Str_SetPtrW(&pfpi->pszName, NULL);
  681.         Str_SetPtrW(&pfpi->pszLocation, NULL);
  682.         Str_SetPtrW(&pfpi->pszModel, NULL);
  683.         LocalFree(pfpi);               // free the parameters we were given
  684.     }
  685. }
  686. HRESULT _SetStrToPropertyBag(IPropertyBag *ppb, LPCWSTR pszProperty, LPCWSTR pszValue)
  687. {
  688.     VARIANT variant = { 0 };
  689.     V_VT(&variant) = VT_BSTR;
  690.     V_BSTR(&variant) = SysAllocString(pszValue);
  691.     if ( !V_BSTR(&variant) )
  692.         return E_OUTOFMEMORY;
  693.     HRESULT hres = ppb->Write(pszProperty, &variant);
  694.     SysFreeString(V_BSTR(&variant));    
  695.     return hres;
  696. }
  697. HRESULT _GetPrintPropertyBag(FINDPRINTERINFO *pfpi, IPropertyBag **pppb)
  698. {
  699.     HRESULT hres = S_OK;
  700.     IPropertyBag *ppb = NULL;
  701.     // if we have properties that need to be passed then lets package them up
  702.     // into a property bag.
  703.     if ( pfpi->pszName || pfpi->pszLocation || pfpi->pszModel )
  704.     {
  705.         hres = SHCreatePropertyBag(IID_IPropertyBag, (void **)&ppb);
  706.         if ( SUCCEEDED(hres) )
  707.         {
  708.             if ( pfpi->pszName )
  709.                 hres = _SetStrToPropertyBag(ppb, L"printName", pfpi->pszName);
  710.             if ( pfpi->pszLocation && SUCCEEDED(hres) )
  711.                 hres = _SetStrToPropertyBag(ppb, L"printLocation", pfpi->pszLocation);
  712.             if ( pfpi->pszModel && SUCCEEDED(hres) )
  713.                 hres = _SetStrToPropertyBag(ppb, L"printModel", pfpi->pszModel);
  714.         }
  715.     }
  716.     if ( FAILED(hres) && ppb )
  717.         ppb->Release();
  718.     else
  719.         *pppb = ppb;
  720.     return hres;
  721. }
  722. DWORD WINAPI _FindPrinterThreadProc(void *ptp)
  723. {
  724.     FINDPRINTERINFO *pfpi = (FINDPRINTERINFO*)ptp;
  725.     ICommonQuery *pcq;
  726.     if (SUCCEEDED(CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER, IID_ICommonQuery, (void **)&pcq)))
  727.     {
  728.         OPENQUERYWINDOW oqw = { 0 };
  729.         oqw.cbStruct = SIZEOF(oqw);
  730.         oqw.dwFlags = OQWF_DEFAULTFORM | OQWF_REMOVEFORMS | OQWF_PARAMISPROPERTYBAG;
  731.         oqw.clsidHandler = CLSID_DsQuery;
  732.         oqw.clsidDefaultForm = CLSID_DsFindPrinter;
  733.     
  734.         if ( SUCCEEDED(_GetPrintPropertyBag(pfpi, &oqw.ppbFormParameters)) )
  735.             pcq->OpenQueryWindow(NULL, &oqw, NULL);
  736.         if ( oqw.pFormParameters )
  737.             oqw.ppbFormParameters->Release();
  738.         pcq->Release();
  739.     }
  740.     _FreeFindPrinterInfo(pfpi);
  741.     return 0;
  742. }
  743. STDMETHODIMP CShellDispatch::FindPrinter(BSTR name, BSTR location, BSTR model)
  744. {
  745.     if (!FAllowUserToDoAnything())
  746.         return E_ACCESSDENIED;
  747.     // bundle the parameters to pass over to the bg thread which will issue the query
  748.     FINDPRINTERINFO *pfpi = (FINDPRINTERINFO*)LocalAlloc(LPTR, SIZEOF(FINDPRINTERINFO));
  749.     if ( !pfpi )
  750.         return E_OUTOFMEMORY;
  751.     if ( Str_SetPtrW(&pfpi->pszName, name) && 
  752.          Str_SetPtrW(&pfpi->pszLocation, location) && 
  753.          Str_SetPtrW(&pfpi->pszModel, model) )
  754.     {
  755.         if (SHCreateThread(_FindPrinterThreadProc, pfpi, CTF_PROCESS_REF | CTF_COINIT, NULL))
  756.         {
  757.             pfpi = NULL;            // thread owns
  758.         }
  759.     }
  760.     // either close the thread handle, or release the parameter block.   we assume
  761.     // that if the thread was created it will handle discarding the block.
  762.     if (pfpi)
  763.         _FreeFindPrinterInfo(pfpi);
  764.     return S_OK;
  765. }
  766. #ifdef WINNT
  767. // NT4 returns a good processor level in wProcessorLevel
  768. #define _GetProcessorLevelFromSystemInfo(pinfo) (pinfo)->wProcessorLevel
  769. #else
  770. // Win95 doesn't support SYSTEM_INFO.wProcessorLevel so we have
  771. // to do it the hard way.  Win98 does support it, but that's scant
  772. // consolation.
  773. UINT _GetProcessorLevelFromSystemInfo(SYSTEM_INFO *pinfo)
  774. {
  775.     UINT uiLevel = 0;
  776.     switch (pinfo->dwProcessorType)
  777.     {
  778.     case PROCESSOR_INTEL_386:
  779.         uiLevel = 3;
  780.         break;
  781.     case PROCESSOR_INTEL_486:
  782.         uiLevel = 4;
  783.     // We'll assume that everything Pentium or better supports CPUID
  784.     // But just in case, we'll wrap this inside a try/except.
  785.     default:
  786.         __try {
  787.             // The CPUID instruction trashes EBX but the compiler doesn't know
  788.             // that so we have to trash it explicitly
  789.             _asm {
  790.                 xor eax, eax
  791.                 inc eax
  792.                 _emit 0x0F          // CPUID
  793.                 _emit 0xA2
  794.                 xor ebx, ebx        // so compiler doesn't assume ebx is preserved
  795.                 and ah, 15          // Processor level returned in low nibble of ah
  796.                 mov byte ptr uiLevel, ah
  797.             }
  798.         } __except (EXCEPTION_EXECUTE_HANDLER) { }
  799.         break;
  800.     }
  801.     return uiLevel;
  802. }
  803. #endif
  804. STDMETHODIMP CShellDispatch::GetSystemInformation(BSTR bstrName, VARIANT * pvOut)
  805. {
  806.     if (!FAllowUserToDoAnything())
  807.         return E_ACCESSDENIED;
  808.     
  809.     TCHAR szName[MAX_PATH];
  810.     SHUnicodeToTCharCP(CP_ACP, bstrName, szName, ARRAYSIZE(szName));
  811.     if (!lstrcmpi(szName, TEXT("DirectoryServiceAvailable")))
  812.     {
  813.         pvOut->vt = VT_BOOL;
  814.         V_BOOL(pvOut) = GetEnvironmentVariable(TEXT("USERDNSDOMAIN"), NULL, 0) > 0;
  815.         return S_OK;
  816.     }
  817.     else if (!lstrcmpi(szName, TEXT("DoubleClickTime")))
  818.     {
  819.         pvOut->vt = VT_UI4;
  820.         V_UI4(pvOut) = GetDoubleClickTime();
  821.         return S_OK;
  822.     }
  823.     else if (!lstrcmpi(szName, TEXT("ProcessorLevel")))
  824.     {
  825.         SYSTEM_INFO info;
  826.         GetSystemInfo(&info);
  827.         pvOut->vt = VT_I4;
  828.         V_UI4(pvOut) = _GetProcessorLevelFromSystemInfo(&info);
  829.         return S_OK;
  830.     }
  831.     else if (!lstrcmpi(szName, TEXT("ProcessorSpeed")))
  832.     {
  833.         HKEY hkey;
  834.         if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
  835.                                           TEXT("Hardware\Description\System\CentralProcessor\0"), 
  836.                                           0, KEY_READ, &hkey))
  837.             return E_FAIL;
  838.         DWORD dwValue = 0;
  839.         DWORD cb = sizeof( dwValue );
  840.         if (ERROR_SUCCESS != SHQueryValueEx(hkey,
  841.                     TEXT("~Mhz"),
  842.                     NULL,
  843.                     NULL,
  844.                     (LPBYTE) &dwValue,
  845.                     &cb) == ERROR_SUCCESS) 
  846.         {       
  847.             RegCloseKey(hkey);
  848.             return E_FAIL;
  849.         }
  850.         RegCloseKey(hkey);
  851.         pvOut->vt = VT_I4;
  852.         V_UI4(pvOut) = dwValue;
  853.         return S_OK;
  854.     }
  855.     else if (!lstrcmpi(szName, TEXT("ProcessorArchitecture")))
  856.     {
  857.         SYSTEM_INFO info;
  858.         GetSystemInfo(&info);
  859.         pvOut->vt = VT_I4;
  860.         V_UI4(pvOut) = info.wProcessorArchitecture;
  861.         return S_OK;
  862.     }
  863.     else if (!lstrcmpi(szName, TEXT("PhysicalMemoryInstalled")))
  864.     {
  865.         MEMORYSTATUSEX MemoryStatus;
  866.         MemoryStatus.dwLength = SIZEOF(MEMORYSTATUSEX);
  867.         NT5_GlobalMemoryStatusEx(&MemoryStatus);
  868.         pvOut->vt = VT_R8;
  869.         V_R8(pvOut) = (double)(signed __int64) MemoryStatus.ullTotalPhys;
  870.         return S_OK;
  871.     }
  872.     else
  873.     {
  874.         return E_INVALIDARG;
  875.     }
  876. }
  877. #endif // POSTSPLIT