// PropBrowseCtl.cpp : Implementation of a property browser control // // This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #include "stdafx.h" #include "ATLCon.h" #include "PropBrowseCtl.h" ///////////////////////////////////////////////////////////////////////////// // CPropertyBrowseControl #include LRESULT CPropertyBrowseControl::OnCreate(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DefWindowProc(); RECT rc; GetClientRect(&rc); m_list.Create(this, 1, m_hWnd, &rc, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 101); m_list.SetExtendedListViewStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); HFONT hFont = m_list.GetFont(); m_list.AddColumn(_T("Name"), 0); m_list.AddColumn(_T("Value"), 1); TEXTMETRIC tm; HDC hdc = ::GetDC(NULL); HFONT hOldFont = (HFONT)::SelectObject(hdc, hFont); ::GetTextMetrics(hdc, &tm); ::SelectObject(hdc, hOldFont); ::ReleaseDC(NULL, hdc); m_nHeightDesc = (tm.tmHeight+tm.tmExternalLeading)*3; //room for three lines of text rc.bottom -= m_nHeightDesc; m_list.MoveWindow(&rc); RECT rc2 = {0,0,0,0}; m_edit.Create(this, 2, m_list, &rc2); m_edit.SetFont(hFont); // combobox has ID of 103 m_combobox.Create(this, 3, m_list, &rc2, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 103); m_combobox.SetFont(hFont); rc.top = rc.bottom; rc.bottom += m_nHeightDesc; m_wndDesc.Create(this, 4, m_hWnd, &rc2, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 104); m_wndDesc.SetFont(hFont); return 0; } LRESULT CPropertyBrowseControl::OnNotify(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { USES_CONVERSION; NMLISTVIEW* pnmlv = (NMLISTVIEW*) lParam; if (pnmlv->hdr.code == LVN_ITEMCHANGED) { NMLISTVIEW* pnmlv = (NMLISTVIEW*) lParam; if (pnmlv->uNewState & LVIS_FOCUSED) { CProperty* pProp = (CProperty*)m_list.GetItemData(pnmlv->iItem); LPCTSTR lpszDesc = (pProp == NULL) ? _T("") : OLE2T(pProp->m_bstrDesc); m_wndDesc.SetWindowText(lpszDesc); } } if (pnmlv->hdr.code == NM_RETURN) { pnmlv->hdr.code = NM_DBLCLK; pnmlv->iItem = m_list.GetSelectedIndex(); pnmlv->iSubItem = 1; } if ((pnmlv->hdr.code == NM_DBLCLK) || (pnmlv->hdr.code == NM_CLICK)) { if (pnmlv->iSubItem == 1) { RECT rc; m_nItem = pnmlv->iItem; m_nSubItem = pnmlv->iSubItem; CComBSTR bstrText; m_list.GetItemText(m_nItem, m_nSubItem, bstrText.m_str); m_list.GetSubItemRect(m_nItem, m_nSubItem, 0, &rc); LPCTSTR lpszText = OLE2T(bstrText); CProperty* pProp = (CProperty*)m_list.GetItemData(pnmlv->iItem); if (pProp != NULL) { if (!pProp->IsCombo()) // use edit control if not an enum { m_edit.SetWindowText(lpszText ? lpszText : _T("")); rc.top -= 2; rc.bottom -= 2; m_edit.MoveWindow(&rc); m_edit.SetFocus(); } else { pProp->AddEnumValues(m_combobox); // m_combobox.SetWindowText(lpszText ? lpszText : _T("")); int nHeight = m_combobox.GetItemHeight(-1); int nOffset = (nHeight-(rc.bottom-rc.top))/2 + 2; rc.bottom -= nOffset; rc.top -= nOffset; rc.bottom += 100; m_combobox.MoveWindow(&rc); m_combobox.SetFocus(); } } } else { RECT rc = {0,0,0,0}; m_combobox.MoveWindow(&rc); m_edit.MoveWindow(&rc); } } return 0; } LRESULT CPropertyBrowseControl::OnChar(UINT nMessage, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { TCHAR ch = (TCHAR) wParam; if (ch == VK_RETURN) { USES_CONVERSION; RECT rc = {0,0,0,0}; m_edit.MoveWindow(&rc); CComBSTR bstrText; m_edit.GetWindowText(bstrText.m_str); m_list.SetItemText(m_nItem, m_nSubItem, OLE2T(bstrText)); m_list.SetFocus(); CProperty* pProp = (CProperty*)m_list.GetItemData(m_nItem); pProp->SetValue(OLE2T(bstrText)); return 0; } return m_edit.DefWindowProc(); } HRESULT CPropertyBrowseControl::AddDispatch(IDispatch* pDisp) { USES_CONVERSION; CComPtr spTypeInfo; if (pDisp == NULL) return S_OK; pDisp->GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, &spTypeInfo); if (spTypeInfo == NULL) return E_FAIL; TYPEATTR* pta; spTypeInfo->GetTypeAttr(&pta); if (pta->typekind == TKIND_INTERFACE) { // Get the dual CComPtr spInfoTemp; HREFTYPE hRef; HRESULT hr = spTypeInfo->GetRefTypeOfImplType(-1, &hRef); if (FAILED(hr)) return E_FAIL; hr = spTypeInfo->GetRefTypeInfo(hRef, &spInfoTemp); if (FAILED(hr)) return E_FAIL; spTypeInfo->ReleaseTypeAttr(pta); spTypeInfo = spInfoTemp; spTypeInfo->GetTypeAttr(&pta); } int item = m_list.GetItemCount(); for (int i=0; icFuncs; i++) { FUNCDESC* pfd; spTypeInfo->GetFuncDesc(i, &pfd); if (pfd->invkind & DISPATCH_PROPERTYGET && (pfd->wFuncFlags & (FUNCFLAG_FRESTRICTED | FUNCFLAG_FHIDDEN)) == 0) { switch (pfd->elemdescFunc.tdesc.vt) { case VT_USERDEFINED: case VT_EMPTY: case VT_NULL: case VT_I2: case VT_I4: case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_BSTR: case VT_ERROR: case VT_BOOL: case VT_VARIANT: case VT_DECIMAL: case VT_I1: case VT_UI1: case VT_UI2: case VT_UI4: case VT_INT: case VT_UINT: { CComPtr spUserTypeInfo; if (pfd->elemdescFunc.tdesc.vt == VT_USERDEFINED) { HREFTYPE hrt = pfd->elemdescFunc.tdesc.hreftype; VARTYPE vt = VT_USERDEFINED; HRESULT hr = E_FAIL; hr = GetEnumTypeInfo(spTypeInfo, hrt, &spUserTypeInfo); if(FAILED(hr)) vt = GetUserDefinedType(spTypeInfo, hrt); } USES_CONVERSION; CComVariant varVal; CComBSTR bstrVal; CComBSTR bstrName; CComBSTR bstrDocString; spTypeInfo->GetDocumentation(pfd->memid, &bstrName, &bstrDocString, NULL, NULL); CComDispatchDriver dd(pDisp); dd.GetProperty(pfd->memid, &varVal); CProperty* pProp = new CProperty(pDisp, pfd->memid, varVal, bstrDocString, spUserTypeInfo); pProp->GetStringValue(&bstrVal); m_list.AddItem(item, 0, OLE2T(bstrName)); m_list.AddItem(item, 1, OLE2T(bstrVal)); m_list.SetItemData(item, reinterpret_cast(pProp)); item++; } } } spTypeInfo->ReleaseFuncDesc(pfd); } spTypeInfo->ReleaseTypeAttr(pta); return S_OK; } STDMETHODIMP CPropertyBrowseControl::put_Dispatch(IDispatch* pDisp) { USES_CONVERSION; ClearListView(); m_spDispatch = pDisp; if (pDisp != NULL) { m_list.SetRedraw(FALSE); AddDispatch(pDisp); m_list.SetRedraw(TRUE); m_list.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); m_list.SetColumnWidth(1, LVSCW_AUTOSIZE_USEHEADER); } return S_OK; } STDMETHODIMP CPropertyBrowseControl::get_Dispatch(IDispatch** ppDisp) { return m_spDispatch.CopyTo(ppDisp); } STDMETHODIMP CPropertyBrowseControl::get_ShowDescription(BOOL *pVal) { *pVal = m_bShowDesc ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP CPropertyBrowseControl::put_ShowDescription(BOOL newVal) { m_bShowDesc = (newVal == VARIANT_TRUE); RECT rc; GetWindowRect(&rc); if (m_bShowDesc) rc.bottom -= m_nHeightDesc; m_list.MoveWindow(&rc); return S_OK; }