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.

638 lines
17 KiB

  1. // util.cpp - miscelaneous helper functions
  2. #include "stdafx.h"
  3. #include "util.h"
  4. // Net API stuffs
  5. #include <dsgetdc.h>
  6. #include <wtsapi32.h>
  7. #include <rassapi.h>
  8. #include <shlobj.h>
  9. #include <lmaccess.h>
  10. #include <lmapibuf.h>
  11. #include <lmshare.h>
  12. #include <lmserver.h>
  13. // ldap/adsi includes
  14. #include <iads.h>
  15. #include <adshlp.h>
  16. #include <adsiid.h>
  17. extern HWND g_hwndMain;
  18. LRESULT CALLBACK EventCBWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  19. // Event callback window class object
  20. CMsgWindowClass EventCBWndClass(L"OnEventCB", EventCBWndProc);
  21. HBITMAP GetBitmapFromStrip(HBITMAP hbmStrip, int nPos, int cSize)
  22. {
  23. HBITMAP hbmNew = NULL;
  24. // Create src & dest DC
  25. HDC hdc = GetDC(NULL);
  26. if( hdc == NULL ) return NULL;
  27. HDC hdcSrc = CreateCompatibleDC(hdc);
  28. HDC hdcDst = CreateCompatibleDC(hdc);
  29. if( hdcSrc && hdcDst )
  30. {
  31. hbmNew= CreateCompatibleBitmap (hdc, cSize, cSize);
  32. if( hbmNew )
  33. {
  34. // Select src & dest bitmaps into DCs
  35. HBITMAP hbmSrcOld = (HBITMAP)SelectObject(hdcSrc, (HGDIOBJ)hbmStrip);
  36. HBITMAP hbmDstOld = (HBITMAP)SelectObject(hdcDst, (HGDIOBJ)hbmNew);
  37. // Copy selected image from source
  38. BitBlt(hdcDst, 0, 0, cSize, cSize, hdcSrc, cSize * nPos, 0, SRCCOPY);
  39. // Restore selections
  40. if( hbmSrcOld ) SelectObject(hdcSrc, (HGDIOBJ)hbmSrcOld);
  41. if( hbmDstOld ) SelectObject(hdcDst, (HGDIOBJ)hbmDstOld);
  42. }
  43. DeleteDC(hdcSrc);
  44. DeleteDC(hdcDst);
  45. }
  46. ReleaseDC(NULL, hdc);
  47. return hbmNew;
  48. }
  49. void ConfigSingleColumnListView(HWND hwndListView)
  50. {
  51. if( !hwndListView || !::IsWindow(hwndListView) ) return;
  52. RECT rc;
  53. BOOL bStat = GetClientRect(hwndListView, &rc);
  54. ASSERT(bStat);
  55. LV_COLUMN lvc;
  56. lvc.mask = LVCF_WIDTH | LVCF_SUBITEM;
  57. lvc.cx = rc.right - rc.left - GetSystemMetrics(SM_CXVSCROLL);
  58. lvc.iSubItem = 0;
  59. int iCol = ListView_InsertColumn(hwndListView, 0, &lvc);
  60. ASSERT(iCol == 0);
  61. ListView_SetExtendedListViewStyleEx(hwndListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
  62. }
  63. //--------------------------------------------------------------------------
  64. // EnableDlgItem
  65. //
  66. // Enables or disables a dialog control. If the control has the focus when
  67. // it is disabled, the focus is moved to the next control
  68. //--------------------------------------------------------------------------
  69. void EnableDlgItem(HWND hwndDialog, int iCtrlID, BOOL bEnable)
  70. {
  71. if( !hwndDialog || !::IsWindow(hwndDialog) ) return;
  72. HWND hWndCtrl = ::GetDlgItem(hwndDialog, iCtrlID);
  73. if( !hWndCtrl || !::IsWindow(hWndCtrl) ) return;
  74. if( !bEnable && ::GetFocus() == hWndCtrl )
  75. {
  76. HWND hWndNextCtrl = ::GetNextDlgTabItem(hwndDialog, hWndCtrl, FALSE);
  77. if( hWndNextCtrl != NULL && hWndNextCtrl != hWndCtrl )
  78. {
  79. ::SetFocus(hWndNextCtrl);
  80. }
  81. }
  82. ::EnableWindow(hWndCtrl, bEnable);
  83. }
  84. //--------------------------------------------------------------------------
  85. // GetItemText
  86. //
  87. // Read text from a control and return it in a string
  88. //---------------------------------------------------------------------------
  89. void GetItemText(HWND hwnd, tstring& strText)
  90. {
  91. strText = _T("");
  92. if( !hwnd || !::IsWindow(hwnd) ) return;
  93. int nLen = ::GetWindowTextLength(hwnd);
  94. if( nLen == 0 ) return;
  95. LPWSTR pszTemp = new WCHAR[nLen + 1];
  96. if( !pszTemp ) return;
  97. int nLen1 = ::GetWindowText( hwnd, pszTemp, (nLen + 1) );
  98. ASSERT(nLen == nLen1);
  99. strText = pszTemp;
  100. delete [] pszTemp;
  101. }
  102. //------------------------------------------------------------------------
  103. // RemoveSpaces
  104. //
  105. // Remove spaces from null-terminated string
  106. //-------------------------------------------------------------------------
  107. void RemoveSpaces(LPWSTR pszBuf)
  108. {
  109. if( !pszBuf ) return;
  110. WCHAR* pszDest = pszBuf;
  111. do
  112. {
  113. if( *pszBuf != L' ' ) *(pszDest++) = *pszBuf;
  114. }
  115. while( *(pszBuf++) );
  116. }
  117. //-------------------------------------------------------------------------
  118. // EscapeSlashes
  119. //
  120. // Add escape char '\' in front of each forward slash '/'
  121. //-------------------------------------------------------------------------
  122. void EscapeSlashes(LPCWSTR pszIn, tstring& strOut)
  123. {
  124. strOut = _T("");
  125. if( !pszIn ) return;
  126. strOut.reserve( wcslen(pszIn) + 8 );
  127. while( *pszIn != 0 )
  128. {
  129. if( *pszIn == L'/' )
  130. strOut += L'\\';
  131. strOut += *(pszIn++);
  132. }
  133. }
  134. HRESULT ReplaceParameters( tstring& str, CParamLookup& lookup, BOOL bRetainMarkers )
  135. {
  136. // Do for each parameter $<param name>
  137. int posParam = 0;
  138. while( (posParam = str.find(L"$<", posParam)) != tstring::npos )
  139. {
  140. // skip over the '$<'
  141. posParam += 2;
  142. // find terminating ">"
  143. int posParamEnd = str.find(L">", posParam);
  144. if( posParamEnd == tstring::npos )
  145. return E_FAIL;
  146. // Get replacement string from lookup function
  147. tstring strValue;
  148. if( !lookup(str.substr(posParam, posParamEnd - posParam), strValue) )
  149. return E_FAIL;
  150. // replace either paramter or parameter and markers
  151. // and advance pointer to first char after substitution
  152. if( bRetainMarkers )
  153. {
  154. str.replace(posParam, posParamEnd - posParam, strValue);
  155. posParam += strValue.size();
  156. }
  157. else
  158. {
  159. str.replace(posParam - 2, posParamEnd - posParam + 3, strValue);
  160. posParam += strValue.size() - 2;
  161. }
  162. }
  163. return S_OK;
  164. }
  165. VARIANT GetDomainPath( LPCTSTR lpServer )
  166. {
  167. VARIANT vDomain;
  168. ::VariantInit(&vDomain);
  169. if( !lpServer ) return vDomain;
  170. // get the domain information
  171. TCHAR pString[MAX_PATH*2];
  172. _sntprintf( pString, (MAX_PATH*2)-1, L"LDAP://%s/rootDSE", lpServer );
  173. CComPtr<IADs> pDS = NULL;
  174. HRESULT hr = ::ADsGetObject(pString, IID_IADs, (void**)&pDS);
  175. ASSERT(hr == S_OK);
  176. if( hr != S_OK ) return vDomain;
  177. CComBSTR bstrProp = L"defaultNamingContext";
  178. hr = pDS->Get( bstrProp, &vDomain );
  179. ASSERT(hr == S_OK);
  180. return vDomain;
  181. }
  182. HRESULT ExpandDCWildCard( tstring& str )
  183. {
  184. int posParam = 0;
  185. const tstring strKey = _T("DC=*");
  186. if( (posParam = str.find(strKey.c_str(), posParam)) != tstring::npos )
  187. {
  188. CComVariant vDomain;
  189. HRESULT hr = S_OK;
  190. CString csDns = L"";
  191. PDOMAIN_CONTROLLER_INFO pDCI = NULL;
  192. hr = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME, &pDCI);
  193. if( (hr == S_OK) && (pDCI != NULL) )
  194. {
  195. csDns = pDCI->DomainName;
  196. NetApiBufferFree (pDCI);
  197. pDCI = NULL;
  198. }
  199. vDomain = GetDomainPath((LPCTSTR)csDns);
  200. if( vDomain.vt == VT_BSTR )
  201. {
  202. // Get replacement string from lookup function
  203. tstring strValue = vDomain.bstrVal;
  204. // We replace the whole DC=* with the full DC=XYZ,DC=COM
  205. str.replace(posParam, strKey.size(), strValue);
  206. }
  207. else
  208. {
  209. return E_FAIL;
  210. }
  211. }
  212. return S_OK;
  213. }
  214. HRESULT ExpandEnvironmentParams( tstring& strIn, tstring& strOut )
  215. {
  216. // if no % then just return inout string
  217. if( strIn.find(L"%") == tstring::npos )
  218. {
  219. strOut = strIn;
  220. return S_OK;
  221. }
  222. DWORD dwSize = strIn.size() * 2;
  223. while( TRUE )
  224. {
  225. WCHAR* pszBuf = new WCHAR [dwSize];
  226. if( !pszBuf ) return E_OUTOFMEMORY;
  227. ZeroMemory( pszBuf, (dwSize * sizeof(WCHAR)) );
  228. DWORD dwReqSize = ExpandEnvironmentStrings(strIn.c_str(), pszBuf, dwSize);
  229. if( dwReqSize <= dwSize )
  230. {
  231. strOut = pszBuf;
  232. delete [] pszBuf;
  233. return S_OK;
  234. }
  235. delete [] pszBuf;
  236. dwSize = dwReqSize;
  237. }
  238. }
  239. tstring StrLoadString( UINT uID )
  240. {
  241. tstring strRet = _T("");
  242. HINSTANCE hInst = _Module.GetResourceInstance();
  243. INT iSize = MAX_PATH;
  244. TCHAR* psz = new TCHAR[iSize];
  245. if( !psz ) return strRet;
  246. while( LoadString(hInst, uID, psz, iSize) == (iSize - 1) )
  247. {
  248. iSize += MAX_PATH;
  249. delete[] psz;
  250. psz = NULL;
  251. psz = new TCHAR[iSize];
  252. if( !psz ) return strRet;
  253. }
  254. strRet = psz;
  255. delete[] psz;
  256. return strRet;
  257. }
  258. HRESULT StringTableWrite(IStringTable* pStringTable, LPCWSTR psz, MMC_STRING_ID* pID)
  259. {
  260. VALIDATE_POINTER(pStringTable);
  261. VALIDATE_POINTER(psz);
  262. VALIDATE_POINTER(pID);
  263. MMC_STRING_ID newID = 0;
  264. // if non-null string store it and get the new ID
  265. if( psz[0] != 0 )
  266. {
  267. HRESULT hr = pStringTable->AddString(psz, &newID);
  268. ASSERT(SUCCEEDED(hr) && newID != 0);
  269. RETURN_ON_FAILURE(hr);
  270. }
  271. // If had an old string ID, free it
  272. if( *pID != 0 )
  273. {
  274. HRESULT hr = pStringTable->DeleteString(*pID);
  275. ASSERT(SUCCEEDED(hr));
  276. }
  277. *pID = newID;
  278. return S_OK;
  279. }
  280. HRESULT StringTableRead(IStringTable* pStringTable, MMC_STRING_ID ID, tstring& str)
  281. {
  282. VALIDATE_POINTER(pStringTable);
  283. ASSERT(ID != 0);
  284. // get the length of the string from the string table
  285. DWORD cb = 0;
  286. HRESULT hr = pStringTable->GetStringLength(ID, &cb);
  287. RETURN_ON_FAILURE(hr);
  288. // alloc stack buffer (+1 for terminating null)
  289. cb++;
  290. LPWSTR pszBuf = new WCHAR[cb + 1];
  291. if( !pszBuf ) return E_OUTOFMEMORY;
  292. // read the string
  293. DWORD cbRead = 0;
  294. hr = pStringTable->GetString(ID, cb, pszBuf, &cbRead);
  295. RETURN_ON_FAILURE(hr);
  296. ASSERT(cb == cbRead + 1);
  297. str = pszBuf;
  298. delete [] pszBuf;
  299. return S_OK;
  300. }
  301. int DisplayMessageBox(HWND hWnd, UINT uTitleID, UINT uMsgID, UINT uStyle, LPCWSTR pvParam1, LPCWSTR pvParam2)
  302. {
  303. ASSERT(hWnd != NULL || g_hwndMain != NULL);
  304. if( hWnd == NULL && g_hwndMain == NULL )
  305. return 0;
  306. // Display error message
  307. CString strTitle;
  308. strTitle.LoadString(uTitleID);
  309. CString strMsgFmt;
  310. strMsgFmt.LoadString(uMsgID);
  311. CString strMsg;
  312. strMsg.Format(strMsgFmt, pvParam1, pvParam2);
  313. return MessageBox(hWnd ? hWnd : g_hwndMain, strMsg, strTitle, uStyle);
  314. }
  315. HRESULT ValidateFile( tstring& strFilePath )
  316. {
  317. if( strFilePath.empty() ) return E_INVALIDARG;
  318. tstring strTmp;
  319. ExpandEnvironmentParams(strFilePath, strTmp);
  320. // if file path includes a directory or drive specifier then check the specific file
  321. // then look for that specific file
  322. if( strFilePath.find_first_of(L"\\:") != tstring::npos )
  323. {
  324. DWORD dwAttr = GetFileAttributes(strTmp.c_str());
  325. if( (dwAttr != INVALID_FILE_ATTRIBUTES) && !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) )
  326. return S_OK;
  327. }
  328. else
  329. {
  330. // else search for file in standard locations
  331. DWORD dwLen = SearchPath(NULL, strTmp.c_str(), NULL, 0, NULL, NULL);
  332. if( dwLen > 0 )
  333. return S_OK;
  334. }
  335. return E_FAIL;
  336. }
  337. HRESULT ValidateDirectory( tstring& strDir )
  338. {
  339. if( strDir.empty() ) return E_INVALIDARG;
  340. tstring strTmp;
  341. ExpandEnvironmentParams(strDir, strTmp);
  342. DWORD dwAttr = GetFileAttributes( strTmp.c_str() );
  343. if( (dwAttr != INVALID_FILE_ATTRIBUTES) && (dwAttr & FILE_ATTRIBUTE_DIRECTORY) )
  344. return S_OK;
  345. else
  346. return E_FAIL;
  347. }
  348. /////////////////////////////////////////////////////////////////////////
  349. // Event-triggered callbacks
  350. //
  351. // The main thread can request that a callback be made when an object
  352. // is signaled by calling function CallbackOnEvent. The function starts
  353. // a monitor thread which does a wait on the object. When the object is
  354. // signaled, the thread posts a message to a callback window and exits.
  355. // The callback window, which is owned by the main thread, then executes
  356. // the callback function.
  357. //
  358. // the callback window
  359. static HWND hwndCallback = NULL; // callback window
  360. #define MSG_EVENTCALLBACK (WM_USER+100) // callback message
  361. struct EVENTCB_INFO // callback info struct
  362. {
  363. CEventCallback* pCallback; // callback object to execute
  364. HANDLE hWaitObj; // object that triggers the callback
  365. HANDLE hThread; // monitoring thread
  366. };
  367. //---------------------------------------------------------------------------
  368. // EventCBThdProc
  369. //
  370. // This is the monitoring thread procedure. It just does a wait for the object
  371. // signal, then posts a callback message to the callback window.
  372. //
  373. // Inputs: pVoid ptr to EVENTCB_INFO struct (cast to void*)
  374. //----------------------------------------------------------------------------
  375. static DWORD WINAPI EventCBThdProc(void* pVoid )
  376. {
  377. if( !pVoid ) return 0;
  378. EVENTCB_INFO* pInfo = reinterpret_cast<EVENTCB_INFO*>(pVoid);
  379. ASSERT(pInfo->hWaitObj != NULL && pInfo->pCallback != NULL);
  380. DWORD dwStat = WaitForSingleObject(pInfo->hWaitObj, INFINITE);
  381. ASSERT(dwStat == WAIT_OBJECT_0);
  382. ASSERT(hwndCallback != NULL);
  383. ::PostMessage(hwndCallback, MSG_EVENTCALLBACK, reinterpret_cast<WPARAM>(pInfo), NULL);
  384. return 0;
  385. }
  386. //----------------------------------------------------------------------------------
  387. // EventCBWndProc
  388. //
  389. // This is the callback window's WndProc. When it gets a callback message it
  390. // executes the callback function then destroys the callback function object and
  391. // the callback info struct.
  392. //----------------------------------------------------------------------------------
  393. static LRESULT CALLBACK EventCBWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  394. {
  395. if( uMsg == MSG_EVENTCALLBACK )
  396. {
  397. EVENTCB_INFO* pInfo = reinterpret_cast<EVENTCB_INFO*>(wParam);
  398. if( !pInfo ) return 0;
  399. if( pInfo->pCallback )
  400. {
  401. pInfo->pCallback->Execute();
  402. delete pInfo->pCallback;
  403. pInfo->pCallback = NULL;
  404. }
  405. delete pInfo;
  406. pInfo = NULL;
  407. return 0;
  408. }
  409. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  410. }
  411. //-----------------------------------------------------------------------------------
  412. // CallbackOnEvent
  413. //
  414. // This function accepts an event-triggered callback request. It starts a monitoring
  415. // thread which will cause the callback when the specified object signals.
  416. //
  417. // Inputs: HANDLE hWaitObj Handle of object to wait on
  418. // CEventCallback Callback function object (with single Execute method)
  419. //
  420. // Outputs: HRESULT Result of event trigger setup
  421. //
  422. // Note: The CEventCallback object is destroyed after the callback is executed.
  423. //-----------------------------------------------------------------------------------
  424. HRESULT CallbackOnEvent(HANDLE hWaitObj, CEventCallback* pCallback)
  425. {
  426. ASSERT(pCallback != NULL);
  427. // Create callback window the first time
  428. if( hwndCallback == NULL )
  429. {
  430. hwndCallback = EventCBWndClass.Window();
  431. if( hwndCallback == NULL )
  432. return E_FAIL;
  433. }
  434. // Create a callback info object
  435. EVENTCB_INFO* pInfo = new EVENTCB_INFO;
  436. if( pInfo == NULL )
  437. return E_OUTOFMEMORY;
  438. pInfo->hWaitObj = hWaitObj;
  439. pInfo->pCallback = pCallback;
  440. // Start monitor thread passing it the callback info
  441. pInfo->hThread = CreateThread(NULL, NULL, EventCBThdProc, pInfo, 0, NULL);
  442. if( pInfo->hThread == NULL )
  443. {
  444. delete pInfo;
  445. return E_FAIL;
  446. }
  447. return S_OK;
  448. }
  449. BOOL ModifyStyleEx(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags)
  450. {
  451. if( !hWnd || !::IsWindow(hWnd) ) return FALSE;
  452. DWORD dwStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
  453. DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;
  454. if( dwStyle == dwNewStyle )
  455. return FALSE;
  456. ::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewStyle);
  457. if( nFlags != 0 )
  458. {
  459. ::SetWindowPos(hWnd, NULL, 0, 0, 0, 0,
  460. SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);
  461. }
  462. return TRUE;
  463. }
  464. ///////////////////////////////////////////////////////////////////////////////////////
  465. // CMsgWindowClass
  466. HWND CMsgWindowClass::Window()
  467. {
  468. ASSERT(m_pszName != NULL && m_pWndProc != NULL);
  469. if( m_hWnd != NULL )
  470. return m_hWnd;
  471. // Create callback window the first time (m_hwndCB is static)
  472. if( m_atom == NULL )
  473. {
  474. // first register window class
  475. WNDCLASS wc;
  476. memset(&wc, 0, sizeof(WNDCLASS));
  477. wc.lpfnWndProc = m_pWndProc;
  478. wc.hInstance = _Module.GetModuleInstance();
  479. wc.lpszClassName = m_pszName;
  480. m_atom = RegisterClass(&wc);
  481. DWORD dwError = GetLastError();
  482. ASSERT(m_atom);
  483. }
  484. if( m_atom )
  485. {
  486. m_hWnd = ::CreateWindow(MAKEINTATOM(m_atom), L"", WS_DISABLED, 0,0,0,0,
  487. NULL, NULL, _Module.GetModuleInstance(), NULL);
  488. ASSERT(m_hWnd);
  489. }
  490. return m_hWnd;
  491. }