// util.cpp - miscelaneous helper functions #include "stdafx.h" #include "util.h" // Net API stuffs #include #include #include #include #include #include #include #include // ldap/adsi includes #include #include #include extern HWND g_hwndMain; LRESULT CALLBACK EventCBWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Event callback window class object CMsgWindowClass EventCBWndClass(L"OnEventCB", EventCBWndProc); HBITMAP GetBitmapFromStrip(HBITMAP hbmStrip, int nPos, int cSize) { HBITMAP hbmNew = NULL; // Create src & dest DC HDC hdc = GetDC(NULL); if( hdc == NULL ) return NULL; HDC hdcSrc = CreateCompatibleDC(hdc); HDC hdcDst = CreateCompatibleDC(hdc); if( hdcSrc && hdcDst ) { hbmNew= CreateCompatibleBitmap (hdc, cSize, cSize); if( hbmNew ) { // Select src & dest bitmaps into DCs HBITMAP hbmSrcOld = (HBITMAP)SelectObject(hdcSrc, (HGDIOBJ)hbmStrip); HBITMAP hbmDstOld = (HBITMAP)SelectObject(hdcDst, (HGDIOBJ)hbmNew); // Copy selected image from source BitBlt(hdcDst, 0, 0, cSize, cSize, hdcSrc, cSize * nPos, 0, SRCCOPY); // Restore selections if( hbmSrcOld ) SelectObject(hdcSrc, (HGDIOBJ)hbmSrcOld); if( hbmDstOld ) SelectObject(hdcDst, (HGDIOBJ)hbmDstOld); } DeleteDC(hdcSrc); DeleteDC(hdcDst); } ReleaseDC(NULL, hdc); return hbmNew; } void ConfigSingleColumnListView(HWND hwndListView) { if( !hwndListView || !::IsWindow(hwndListView) ) return; RECT rc; BOOL bStat = GetClientRect(hwndListView, &rc); ASSERT(bStat); LV_COLUMN lvc; lvc.mask = LVCF_WIDTH | LVCF_SUBITEM; lvc.cx = rc.right - rc.left - GetSystemMetrics(SM_CXVSCROLL); lvc.iSubItem = 0; int iCol = ListView_InsertColumn(hwndListView, 0, &lvc); ASSERT(iCol == 0); ListView_SetExtendedListViewStyleEx(hwndListView, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); } //-------------------------------------------------------------------------- // EnableDlgItem // // Enables or disables a dialog control. If the control has the focus when // it is disabled, the focus is moved to the next control //-------------------------------------------------------------------------- void EnableDlgItem(HWND hwndDialog, int iCtrlID, BOOL bEnable) { if( !hwndDialog || !::IsWindow(hwndDialog) ) return; HWND hWndCtrl = ::GetDlgItem(hwndDialog, iCtrlID); if( !hWndCtrl || !::IsWindow(hWndCtrl) ) return; if( !bEnable && ::GetFocus() == hWndCtrl ) { HWND hWndNextCtrl = ::GetNextDlgTabItem(hwndDialog, hWndCtrl, FALSE); if( hWndNextCtrl != NULL && hWndNextCtrl != hWndCtrl ) { ::SetFocus(hWndNextCtrl); } } ::EnableWindow(hWndCtrl, bEnable); } //-------------------------------------------------------------------------- // GetItemText // // Read text from a control and return it in a string //--------------------------------------------------------------------------- void GetItemText(HWND hwnd, tstring& strText) { strText = _T(""); if( !hwnd || !::IsWindow(hwnd) ) return; int nLen = ::GetWindowTextLength(hwnd); if( nLen == 0 ) return; LPWSTR pszTemp = new WCHAR[nLen + 1]; if( !pszTemp ) return; int nLen1 = ::GetWindowText( hwnd, pszTemp, (nLen + 1) ); ASSERT(nLen == nLen1); strText = pszTemp; delete [] pszTemp; } //------------------------------------------------------------------------ // RemoveSpaces // // Remove spaces from null-terminated string //------------------------------------------------------------------------- void RemoveSpaces(LPWSTR pszBuf) { if( !pszBuf ) return; WCHAR* pszDest = pszBuf; do { if( *pszBuf != L' ' ) *(pszDest++) = *pszBuf; } while( *(pszBuf++) ); } //------------------------------------------------------------------------- // EscapeSlashes // // Add escape char '\' in front of each forward slash '/' //------------------------------------------------------------------------- void EscapeSlashes(LPCWSTR pszIn, tstring& strOut) { strOut = _T(""); if( !pszIn ) return; strOut.reserve( wcslen(pszIn) + 8 ); while( *pszIn != 0 ) { if( *pszIn == L'/' ) strOut += L'\\'; strOut += *(pszIn++); } } HRESULT ReplaceParameters( tstring& str, CParamLookup& lookup, BOOL bRetainMarkers ) { // Do for each parameter $ int posParam = 0; while( (posParam = str.find(L"$<", posParam)) != tstring::npos ) { // skip over the '$<' posParam += 2; // find terminating ">" int posParamEnd = str.find(L">", posParam); if( posParamEnd == tstring::npos ) return E_FAIL; // Get replacement string from lookup function tstring strValue; if( !lookup(str.substr(posParam, posParamEnd - posParam), strValue) ) return E_FAIL; // replace either paramter or parameter and markers // and advance pointer to first char after substitution if( bRetainMarkers ) { str.replace(posParam, posParamEnd - posParam, strValue); posParam += strValue.size(); } else { str.replace(posParam - 2, posParamEnd - posParam + 3, strValue); posParam += strValue.size() - 2; } } return S_OK; } VARIANT GetDomainPath( LPCTSTR lpServer ) { VARIANT vDomain; ::VariantInit(&vDomain); if( !lpServer ) return vDomain; // get the domain information TCHAR pString[MAX_PATH*2]; _sntprintf( pString, (MAX_PATH*2)-1, L"LDAP://%s/rootDSE", lpServer ); CComPtr pDS = NULL; HRESULT hr = ::ADsGetObject(pString, IID_IADs, (void**)&pDS); ASSERT(hr == S_OK); if( hr != S_OK ) return vDomain; CComBSTR bstrProp = L"defaultNamingContext"; hr = pDS->Get( bstrProp, &vDomain ); ASSERT(hr == S_OK); return vDomain; } HRESULT ExpandDCWildCard( tstring& str ) { int posParam = 0; const tstring strKey = _T("DC=*"); if( (posParam = str.find(strKey.c_str(), posParam)) != tstring::npos ) { CComVariant vDomain; HRESULT hr = S_OK; CString csDns = L""; PDOMAIN_CONTROLLER_INFO pDCI = NULL; hr = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME, &pDCI); if( (hr == S_OK) && (pDCI != NULL) ) { csDns = pDCI->DomainName; NetApiBufferFree (pDCI); pDCI = NULL; } vDomain = GetDomainPath((LPCTSTR)csDns); if( vDomain.vt == VT_BSTR ) { // Get replacement string from lookup function tstring strValue = vDomain.bstrVal; // We replace the whole DC=* with the full DC=XYZ,DC=COM str.replace(posParam, strKey.size(), strValue); } else { return E_FAIL; } } return S_OK; } HRESULT ExpandEnvironmentParams( tstring& strIn, tstring& strOut ) { // if no % then just return inout string if( strIn.find(L"%") == tstring::npos ) { strOut = strIn; return S_OK; } DWORD dwSize = strIn.size() * 2; while( TRUE ) { WCHAR* pszBuf = new WCHAR [dwSize]; if( !pszBuf ) return E_OUTOFMEMORY; ZeroMemory( pszBuf, (dwSize * sizeof(WCHAR)) ); DWORD dwReqSize = ExpandEnvironmentStrings(strIn.c_str(), pszBuf, dwSize); if( dwReqSize <= dwSize ) { strOut = pszBuf; delete [] pszBuf; return S_OK; } delete [] pszBuf; dwSize = dwReqSize; } } tstring StrLoadString( UINT uID ) { tstring strRet = _T(""); HINSTANCE hInst = _Module.GetResourceInstance(); INT iSize = MAX_PATH; TCHAR* psz = new TCHAR[iSize]; if( !psz ) return strRet; while( LoadString(hInst, uID, psz, iSize) == (iSize - 1) ) { iSize += MAX_PATH; delete[] psz; psz = NULL; psz = new TCHAR[iSize]; if( !psz ) return strRet; } strRet = psz; delete[] psz; return strRet; } HRESULT StringTableWrite(IStringTable* pStringTable, LPCWSTR psz, MMC_STRING_ID* pID) { VALIDATE_POINTER(pStringTable); VALIDATE_POINTER(psz); VALIDATE_POINTER(pID); MMC_STRING_ID newID = 0; // if non-null string store it and get the new ID if( psz[0] != 0 ) { HRESULT hr = pStringTable->AddString(psz, &newID); ASSERT(SUCCEEDED(hr) && newID != 0); RETURN_ON_FAILURE(hr); } // If had an old string ID, free it if( *pID != 0 ) { HRESULT hr = pStringTable->DeleteString(*pID); ASSERT(SUCCEEDED(hr)); } *pID = newID; return S_OK; } HRESULT StringTableRead(IStringTable* pStringTable, MMC_STRING_ID ID, tstring& str) { VALIDATE_POINTER(pStringTable); ASSERT(ID != 0); // get the length of the string from the string table DWORD cb = 0; HRESULT hr = pStringTable->GetStringLength(ID, &cb); RETURN_ON_FAILURE(hr); // alloc stack buffer (+1 for terminating null) cb++; LPWSTR pszBuf = new WCHAR[cb + 1]; if( !pszBuf ) return E_OUTOFMEMORY; // read the string DWORD cbRead = 0; hr = pStringTable->GetString(ID, cb, pszBuf, &cbRead); RETURN_ON_FAILURE(hr); ASSERT(cb == cbRead + 1); str = pszBuf; delete [] pszBuf; return S_OK; } int DisplayMessageBox(HWND hWnd, UINT uTitleID, UINT uMsgID, UINT uStyle, LPCWSTR pvParam1, LPCWSTR pvParam2) { ASSERT(hWnd != NULL || g_hwndMain != NULL); if( hWnd == NULL && g_hwndMain == NULL ) return 0; // Display error message CString strTitle; strTitle.LoadString(uTitleID); CString strMsgFmt; strMsgFmt.LoadString(uMsgID); CString strMsg; strMsg.Format(strMsgFmt, pvParam1, pvParam2); return MessageBox(hWnd ? hWnd : g_hwndMain, strMsg, strTitle, uStyle); } HRESULT ValidateFile( tstring& strFilePath ) { if( strFilePath.empty() ) return E_INVALIDARG; tstring strTmp; ExpandEnvironmentParams(strFilePath, strTmp); // if file path includes a directory or drive specifier then check the specific file // then look for that specific file if( strFilePath.find_first_of(L"\\:") != tstring::npos ) { DWORD dwAttr = GetFileAttributes(strTmp.c_str()); if( (dwAttr != INVALID_FILE_ATTRIBUTES) && !(dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) return S_OK; } else { // else search for file in standard locations DWORD dwLen = SearchPath(NULL, strTmp.c_str(), NULL, 0, NULL, NULL); if( dwLen > 0 ) return S_OK; } return E_FAIL; } HRESULT ValidateDirectory( tstring& strDir ) { if( strDir.empty() ) return E_INVALIDARG; tstring strTmp; ExpandEnvironmentParams(strDir, strTmp); DWORD dwAttr = GetFileAttributes( strTmp.c_str() ); if( (dwAttr != INVALID_FILE_ATTRIBUTES) && (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ) return S_OK; else return E_FAIL; } ///////////////////////////////////////////////////////////////////////// // Event-triggered callbacks // // The main thread can request that a callback be made when an object // is signaled by calling function CallbackOnEvent. The function starts // a monitor thread which does a wait on the object. When the object is // signaled, the thread posts a message to a callback window and exits. // The callback window, which is owned by the main thread, then executes // the callback function. // // the callback window static HWND hwndCallback = NULL; // callback window #define MSG_EVENTCALLBACK (WM_USER+100) // callback message struct EVENTCB_INFO // callback info struct { CEventCallback* pCallback; // callback object to execute HANDLE hWaitObj; // object that triggers the callback HANDLE hThread; // monitoring thread }; //--------------------------------------------------------------------------- // EventCBThdProc // // This is the monitoring thread procedure. It just does a wait for the object // signal, then posts a callback message to the callback window. // // Inputs: pVoid ptr to EVENTCB_INFO struct (cast to void*) //---------------------------------------------------------------------------- static DWORD WINAPI EventCBThdProc(void* pVoid ) { if( !pVoid ) return 0; EVENTCB_INFO* pInfo = reinterpret_cast(pVoid); ASSERT(pInfo->hWaitObj != NULL && pInfo->pCallback != NULL); DWORD dwStat = WaitForSingleObject(pInfo->hWaitObj, INFINITE); ASSERT(dwStat == WAIT_OBJECT_0); ASSERT(hwndCallback != NULL); ::PostMessage(hwndCallback, MSG_EVENTCALLBACK, reinterpret_cast(pInfo), NULL); return 0; } //---------------------------------------------------------------------------------- // EventCBWndProc // // This is the callback window's WndProc. When it gets a callback message it // executes the callback function then destroys the callback function object and // the callback info struct. //---------------------------------------------------------------------------------- static LRESULT CALLBACK EventCBWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if( uMsg == MSG_EVENTCALLBACK ) { EVENTCB_INFO* pInfo = reinterpret_cast(wParam); if( !pInfo ) return 0; if( pInfo->pCallback ) { pInfo->pCallback->Execute(); delete pInfo->pCallback; pInfo->pCallback = NULL; } delete pInfo; pInfo = NULL; return 0; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } //----------------------------------------------------------------------------------- // CallbackOnEvent // // This function accepts an event-triggered callback request. It starts a monitoring // thread which will cause the callback when the specified object signals. // // Inputs: HANDLE hWaitObj Handle of object to wait on // CEventCallback Callback function object (with single Execute method) // // Outputs: HRESULT Result of event trigger setup // // Note: The CEventCallback object is destroyed after the callback is executed. //----------------------------------------------------------------------------------- HRESULT CallbackOnEvent(HANDLE hWaitObj, CEventCallback* pCallback) { ASSERT(pCallback != NULL); // Create callback window the first time if( hwndCallback == NULL ) { hwndCallback = EventCBWndClass.Window(); if( hwndCallback == NULL ) return E_FAIL; } // Create a callback info object EVENTCB_INFO* pInfo = new EVENTCB_INFO; if( pInfo == NULL ) return E_OUTOFMEMORY; pInfo->hWaitObj = hWaitObj; pInfo->pCallback = pCallback; // Start monitor thread passing it the callback info pInfo->hThread = CreateThread(NULL, NULL, EventCBThdProc, pInfo, 0, NULL); if( pInfo->hThread == NULL ) { delete pInfo; return E_FAIL; } return S_OK; } BOOL ModifyStyleEx(HWND hWnd, DWORD dwRemove, DWORD dwAdd, UINT nFlags) { if( !hWnd || !::IsWindow(hWnd) ) return FALSE; DWORD dwStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE); DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd; if( dwStyle == dwNewStyle ) return FALSE; ::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewStyle); if( nFlags != 0 ) { ::SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags); } return TRUE; } /////////////////////////////////////////////////////////////////////////////////////// // CMsgWindowClass HWND CMsgWindowClass::Window() { ASSERT(m_pszName != NULL && m_pWndProc != NULL); if( m_hWnd != NULL ) return m_hWnd; // Create callback window the first time (m_hwndCB is static) if( m_atom == NULL ) { // first register window class WNDCLASS wc; memset(&wc, 0, sizeof(WNDCLASS)); wc.lpfnWndProc = m_pWndProc; wc.hInstance = _Module.GetModuleInstance(); wc.lpszClassName = m_pszName; m_atom = RegisterClass(&wc); DWORD dwError = GetLastError(); ASSERT(m_atom); } if( m_atom ) { m_hWnd = ::CreateWindow(MAKEINTATOM(m_atom), L"", WS_DISABLED, 0,0,0,0, NULL, NULL, _Module.GetModuleInstance(), NULL); ASSERT(m_hWnd); } return m_hWnd; }