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.
485 lines
15 KiB
485 lines
15 KiB
// SelectFile.h : Declaration of the CSelectFile
|
|
|
|
#ifndef __SELECTFILE_H_
|
|
#define __SELECTFILE_H_
|
|
|
|
#include "resource.h" // main symbols
|
|
#include <atlctl.h>
|
|
#include "compatuiCP.h"
|
|
extern "C" {
|
|
#include "shimdb.h"
|
|
}
|
|
|
|
#pragma warning(disable:4786)
|
|
#include <string>
|
|
#include <xstring>
|
|
#include <map>
|
|
#include <locale>
|
|
#include <algorithm>
|
|
#include <vector>
|
|
using namespace std;
|
|
|
|
//
|
|
// Accel containment code
|
|
//
|
|
#include "AccelContainer.h"
|
|
|
|
//
|
|
// in ProgList.cpp
|
|
//
|
|
|
|
BOOL
|
|
ValidateExecutableFile(
|
|
LPCTSTR pszPath,
|
|
BOOL bValidateFileExists
|
|
);
|
|
|
|
//
|
|
// in util.cpp
|
|
//
|
|
wstring
|
|
ShimUnquotePath(
|
|
LPCTSTR pwszFileName
|
|
);
|
|
|
|
BOOL
|
|
ShimExpandEnvironmentVars(
|
|
LPCTSTR lpszCmd,
|
|
CComBSTR& bstr
|
|
);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSelectFile
|
|
class ATL_NO_VTABLE CSelectFile :
|
|
public CComObjectRootEx<CComSingleThreadModel>,
|
|
public CStockPropImpl<CSelectFile, ISelectFile, &IID_ISelectFile, &LIBID_COMPATUILib>,
|
|
public CComCompositeControl<CSelectFile>,
|
|
public IPersistStreamInitImpl<CSelectFile>,
|
|
public IOleControlImpl<CSelectFile>,
|
|
public IOleObjectImpl<CSelectFile>,
|
|
public IOleInPlaceActiveObjectImpl<CSelectFile>,
|
|
public IViewObjectExImpl<CSelectFile>,
|
|
public IOleInPlaceObjectWindowlessImpl<CSelectFile>,
|
|
public CComCoClass<CSelectFile, &CLSID_SelectFile>,
|
|
public ISupportErrorInfo,
|
|
public IPersistPropertyBagImpl<CSelectFile>,
|
|
public IConnectionPointContainerImpl<CSelectFile>,
|
|
public CProxy_ISelectFileEvents< CSelectFile >,
|
|
public IPropertyNotifySinkCP< CSelectFile >,
|
|
public IProvideClassInfo2Impl<&CLSID_SelectFile, &DIID__ISelectFileEvents, &LIBID_COMPATUILib>,
|
|
public CProxy_IProgViewEvents< CSelectFile >
|
|
{
|
|
public:
|
|
CSelectFile() :
|
|
m_dwBrowseFlags(0), m_Safe(this)
|
|
{
|
|
m_bWindowOnly = TRUE;
|
|
m_bTabStop = TRUE;
|
|
m_bMouseActivate = FALSE;
|
|
CalcExtent(m_sizeExtent);
|
|
}
|
|
|
|
DECLARE_REGISTRY_RESOURCEID(IDR_SELECTFILE)
|
|
|
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
|
|
|
BEGIN_COM_MAP(CSelectFile)
|
|
COM_INTERFACE_ENTRY(ISelectFile)
|
|
COM_INTERFACE_ENTRY(IDispatch)
|
|
COM_INTERFACE_ENTRY(IViewObjectEx)
|
|
COM_INTERFACE_ENTRY(IViewObject2)
|
|
COM_INTERFACE_ENTRY(IViewObject)
|
|
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
|
|
COM_INTERFACE_ENTRY(IOleInPlaceObject)
|
|
COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
|
|
COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
|
|
COM_INTERFACE_ENTRY(IOleControl)
|
|
COM_INTERFACE_ENTRY(IOleObject)
|
|
COM_INTERFACE_ENTRY(IPersistStreamInit)
|
|
COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
|
|
// COM_INTERFACE_ENTRY(ISupportErrorInfo)
|
|
// COM_INTERFACE_ENTRY(IConnectionPointContainer)
|
|
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
|
|
|
|
COM_INTERFACE_ENTRY(IProvideClassInfo2)
|
|
COM_INTERFACE_ENTRY(IProvideClassInfo)
|
|
COM_INTERFACE_ENTRY(IPersistPropertyBag)
|
|
|
|
END_COM_MAP()
|
|
|
|
BEGIN_PROP_MAP(CSelectFile)
|
|
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
|
|
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
|
|
PROP_ENTRY("BackColor", DISPID_BACKCOLOR, CLSID_StockColorPage)
|
|
PROP_ENTRY("BackStyle", DISPID_BACKSTYLE, CLSID_NULL)
|
|
// PROP_ENTRY("BorderColor", DISPID_BORDERCOLOR, CLSID_StockColorPage)
|
|
// PROP_ENTRY("BorderVisible", DISPID_BORDERVISIBLE, CLSID_NULL)
|
|
PROP_ENTRY("Enabled", DISPID_ENABLED, CLSID_NULL)
|
|
// Example entries
|
|
// PROP_ENTRY("Property Description", dispid, clsid)
|
|
// PROP_PAGE(CLSID_StockColorPage)
|
|
PROP_ENTRY("Accel", 7, CLSID_NULL)
|
|
PROP_ENTRY("ExternAccel", 8, CLSID_NULL)
|
|
PROP_ENTRY("BrowseBtnCaption", 9, CLSID_NULL)
|
|
END_PROP_MAP()
|
|
|
|
BEGIN_CONNECTION_POINT_MAP(CSelectFile)
|
|
CONNECTION_POINT_ENTRY(DIID__ISelectFileEvents)
|
|
// CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
|
|
CONNECTION_POINT_ENTRY(DIID__IProgViewEvents)
|
|
END_CONNECTION_POINT_MAP()
|
|
|
|
BEGIN_MSG_MAP(CSelectFile)
|
|
COMMAND_HANDLER(IDC_BROWSE, BN_CLICKED, OnClickedBrowse)
|
|
|
|
// MESSAGE_HANDLER(WM_CTLCOLORDLG, OnColorDlg)
|
|
// MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnColorDlg)
|
|
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
|
|
MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
|
|
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
|
|
|
|
CHAIN_MSG_MAP(CComCompositeControl<CSelectFile>)
|
|
|
|
// ALT_MSG_MAP(1)
|
|
|
|
END_MSG_MAP()
|
|
// Handler prototypes:
|
|
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
|
|
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
|
|
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
|
|
|
|
BEGIN_SINK_MAP(CSelectFile)
|
|
//Make sure the Event Handlers have __stdcall calling convention
|
|
END_SINK_MAP()
|
|
|
|
STDMETHOD(OnAmbientPropertyChange)(DISPID dispid)
|
|
{
|
|
if (dispid == DISPID_AMBIENT_BACKCOLOR)
|
|
{
|
|
SetBackgroundColorFromAmbient();
|
|
FireViewChange();
|
|
}
|
|
return IOleControlImpl<CSelectFile>::OnAmbientPropertyChange(dispid);
|
|
}
|
|
|
|
HRESULT FireOnChanged(DISPID dispID) {
|
|
if (dispID == DISPID_ENABLED) {
|
|
|
|
::EnableWindow(GetDlgItem(IDC_EDITFILENAME), m_bEnabled);
|
|
::EnableWindow(GetDlgItem(IDC_BROWSE), m_bEnabled);
|
|
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHOD(GetControlInfo)(CONTROLINFO* pCI) {
|
|
if (NULL == pCI) {
|
|
return E_POINTER;
|
|
}
|
|
|
|
pCI->hAccel = NULL;
|
|
pCI->cAccel = 0;
|
|
pCI->dwFlags = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
// ISupportsErrorInfo
|
|
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
|
|
{
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_ISelectFile,
|
|
};
|
|
for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
|
|
{
|
|
if (InlineIsEqualGUID(*arr[i], riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL* psizel) {
|
|
HRESULT hr = IOleObjectImpl<CSelectFile>::SetExtent(dwDrawAspect, psizel);
|
|
|
|
PositionControls();
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(SetObjectRects)(LPCRECT prcPos, LPCRECT prcClip) {
|
|
IOleInPlaceObjectWindowlessImpl<CSelectFile>::SetObjectRects(prcPos, prcClip);
|
|
|
|
PositionControls(prcPos);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL) {
|
|
HRESULT hr = CComCompositeControl<CSelectFile>::InPlaceActivate(iVerb, prcPosRect);
|
|
|
|
Fire_StateChanged(iVerb);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(UIDeactivate)() {
|
|
HRESULT hr = IOleInPlaceObjectWindowlessImpl<CSelectFile>::UIDeactivate();
|
|
|
|
//
|
|
// We are being deactivated
|
|
// when we loose focus, nuke default button out of here
|
|
//
|
|
|
|
DWORD dwDefBtn = (DWORD)SendMessage(DM_GETDEFID, 0);
|
|
|
|
if (HIWORD(dwDefBtn) == DC_HASDEFID) {
|
|
// SendMessage(DM_SETDEFID, IDC_EDITFILENAME); // basically forget the default button
|
|
dwDefBtn = LOWORD(dwDefBtn);
|
|
DWORD dwStyle = ::GetWindowLong(GetDlgItem(dwDefBtn), GWL_STYLE);
|
|
if (dwStyle & BS_DEFPUSHBUTTON) {
|
|
dwStyle &= ~BS_DEFPUSHBUTTON;
|
|
dwStyle |= BS_PUSHBUTTON;
|
|
SendDlgItemMessage(dwDefBtn, BM_SETSTYLE, dwStyle, TRUE);
|
|
}
|
|
}
|
|
|
|
// send killfocus
|
|
SendMessage(WM_KILLFOCUS);
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
// Manually activate the control
|
|
LRESULT lRes = CComCompositeControl<CSelectFile>::OnMouseActivate(uMsg, wParam, lParam, bHandled);
|
|
m_bMouseActivate = TRUE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL PreTranslateAccelerator(LPMSG pMsg, HRESULT& hrRet);
|
|
|
|
|
|
// IViewObjectEx
|
|
DECLARE_VIEW_STATUS(0)
|
|
|
|
// ISelectFile
|
|
public:
|
|
STDMETHOD(ClearAccel)();
|
|
STDMETHOD(ClearExternAccel)();
|
|
STDMETHOD(get_AccelCmd)(/*[in]*/ LONG lCmd, /*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_AccelCmd)(/*[in]*/ LONG lCmd, /*[in]*/ BSTR newVal);
|
|
STDMETHOD(get_BrowseBtnCaption)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_BrowseBtnCaption)(/*[in]*/ BSTR newVal);
|
|
STDMETHOD(get_ExternAccel)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_ExternAccel)(/*[in]*/ BSTR newVal);
|
|
#if 0
|
|
STDMETHOD(get_Accel)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_Accel)(/*[in]*/ BSTR newVal);
|
|
#endif
|
|
STDMETHOD(get_ErrorCode)(/*[out, retval]*/ long *pVal);
|
|
STDMETHOD(get_FileName)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_FileName)(/*[in]*/ BSTR newVal);
|
|
STDMETHOD(get_BrowseFlags)(/*[out, retval]*/ long *pVal);
|
|
STDMETHOD(put_BrowseFlags)(/*[in]*/ long newVal);
|
|
STDMETHOD(get_BrowseInitialDirectory)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_BrowseInitialDirectory)(/*[in]*/ BSTR newVal);
|
|
STDMETHOD(get_BrowseFilter)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_BrowseFilter)(/*[in]*/ BSTR newVal);
|
|
STDMETHOD(get_BrowseTitle)(/*[out, retval]*/ BSTR *pVal);
|
|
STDMETHOD(put_BrowseTitle)(/*[in]*/ BSTR newVal);
|
|
OLE_COLOR m_clrBackColor;
|
|
LONG m_nBackStyle;
|
|
OLE_COLOR m_clrBorderColor;
|
|
BOOL m_bBorderVisible;
|
|
BOOL m_bEnabled;
|
|
|
|
|
|
// browse dialog props
|
|
CComBSTR m_bstrTitle;
|
|
CComBSTR m_bstrFilter;
|
|
CComBSTR m_bstrInitialDirectory;
|
|
CComBSTR m_bstrFileName;
|
|
DWORD m_dwBrowseFlags;
|
|
DWORD m_dwErrorCode;
|
|
|
|
wstring m_BrowseBtnCaption;
|
|
BOOL m_bMouseActivate;
|
|
|
|
enum { IDD = IDD_SELECTFILE };
|
|
LRESULT OnClickedBrowse(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
|
|
|
|
protected:
|
|
|
|
CSafeObject m_Safe;
|
|
|
|
VOID PositionControls(LPCRECT lprc = NULL) {
|
|
|
|
if (NULL == lprc) {
|
|
lprc = &m_rcPos;
|
|
}
|
|
|
|
if (IsWindow()) {
|
|
// position the edit ctl first
|
|
HDWP hdwp = BeginDeferWindowPos(2);
|
|
HWND hedit = GetDlgItem(IDC_EDITFILENAME);
|
|
HWND hbtn = GetDlgItem(IDC_BROWSE);
|
|
LONG lWidthEdit;
|
|
LONG lWidthBtn;
|
|
RECT rcBtn;
|
|
RECT rcEdit;
|
|
LONG lSpace = ::GetSystemMetrics(SM_CXFRAME);
|
|
|
|
::GetWindowRect(hbtn, &rcBtn); // get the rectangle for the button
|
|
::GetWindowRect(hedit, &rcEdit);
|
|
lWidthBtn = rcBtn.right - rcBtn.left; // width of the button - 1
|
|
lWidthEdit = lprc->right - lprc->left - lSpace - lWidthBtn;
|
|
|
|
hdwp = ::DeferWindowPos(hdwp, hedit, NULL, 0, 0, lWidthEdit, rcEdit.bottom - rcEdit.top, SWP_NOZORDER);
|
|
hdwp = ::DeferWindowPos(hdwp, hbtn, NULL, lWidthEdit + lSpace, 0, lWidthBtn, rcBtn.bottom - rcBtn.top, SWP_NOZORDER);
|
|
::EndDeferWindowPos(hdwp);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
|
|
WORD wCmd = 0;
|
|
|
|
//
|
|
// determine whether we came here with accel
|
|
//
|
|
CComCompositeControl<CSelectFile>::OnSetFocus(uMsg, wParam, lParam, bHandled);
|
|
|
|
if (!m_bMouseActivate) {
|
|
DoVerbUIActivate(&m_rcPos, NULL);
|
|
|
|
if (m_Accel.IsAccelKey(NULL, &wCmd)) {
|
|
//
|
|
// we are to be accelerated
|
|
// we look into the accel cmd to see what is there
|
|
//
|
|
switch(wCmd) {
|
|
case IDC_BROWSE:
|
|
::SetFocus(GetDlgItem(IDC_BROWSE));
|
|
OnClickedBrowse(BN_CLICKED, IDC_BROWSE, GetDlgItem(IDC_BROWSE), bHandled);
|
|
break;
|
|
|
|
case IDC_EDITFILENAME:
|
|
::SetFocus(GetDlgItem(IDC_EDITFILENAME));
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// did we arrive here with the tab?
|
|
//
|
|
if (!IsChild(GetFocus())) {
|
|
if (GetKeyState(VK_TAB) & 0x8000) { // was that the tab key ?
|
|
HWND hwndFirst = GetNextDlgTabItem(NULL, FALSE); // first
|
|
HWND hwndLast = GetNextDlgTabItem(hwndFirst, TRUE);
|
|
|
|
if ((GetKeyState(VK_SHIFT) & 0x8000)) {
|
|
// aha, came here with a shift-tab! -- what is the last control ?
|
|
::SetFocus(hwndLast);
|
|
} else {
|
|
::SetFocus(hwndFirst);
|
|
}
|
|
} else {
|
|
|
|
::SetFocus(GetDlgItem(IDC_EDITFILENAME));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// set the default pushbutton
|
|
//
|
|
SendMessage(DM_SETDEFID, IDC_BROWSE);
|
|
SendDlgItemMessage(IDC_BROWSE, BM_SETSTYLE, BS_DEFPUSHBUTTON);
|
|
|
|
m_bMouseActivate = FALSE;
|
|
bHandled = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
{
|
|
/* // this code sets the same font as the container is using
|
|
// we do not care for now, we're using MS Shell Dlg instead
|
|
|
|
CComVariant varFont;
|
|
HFONT hFont;
|
|
HWND hwnd;
|
|
|
|
HRESULT hr = GetAmbientProperty(DISPID_AMBIENT_FONT, varFont);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
CComQIPtr<IFont, &IID_IFont> pFont (varFont.pdispVal);
|
|
if (SUCCEEDED(pFont->get_hFont(&hFont))) {
|
|
for (hwnd = GetTopWindow(); hwnd != NULL;
|
|
hwnd = ::GetNextWindow(hwnd, GW_HWNDNEXT)) {
|
|
::SendMessage(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
*/
|
|
|
|
SHAutoComplete(GetDlgItem(IDC_EDITFILENAME), SHACF_FILESYSTEM);
|
|
if (m_BrowseBtnCaption.length()) {
|
|
SetDlgItemText(IDC_BROWSE, m_BrowseBtnCaption.c_str());
|
|
}
|
|
|
|
//
|
|
// show ui hints
|
|
//
|
|
|
|
SendMessage(WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS));
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Accelerators
|
|
//
|
|
CAccelContainer m_Accel;
|
|
CAccelContainer m_ExternAccel;
|
|
|
|
BOOL GetFileNameFromUI(wstring& sFileName) {
|
|
BSTR bstrFileName = NULL;
|
|
BOOL bReturn = FALSE;
|
|
bReturn = GetDlgItemText(IDC_EDITFILENAME, bstrFileName);
|
|
if (bReturn) {
|
|
sFileName = ShimUnquotePath(bstrFileName);
|
|
//
|
|
// now also expand environment variables
|
|
//
|
|
if (!sFileName.empty()) {
|
|
CComBSTR bstrExpanded;
|
|
ShimExpandEnvironmentVars(sFileName.c_str(), bstrExpanded);
|
|
sFileName = bstrExpanded;
|
|
}
|
|
|
|
} else {
|
|
sFileName.erase();
|
|
}
|
|
if (bstrFileName) {
|
|
::SysFreeString(bstrFileName);
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
#endif //__SELECTFILE_H_
|