⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dropcombobox.cpp

📁 时间戳生成
💻 CPP
字号:
// DropComboBox.cpp : implementation file
//
// Autocompleting combo-box (like the URL edit box in netscape)
// that accepts dropped files
//
// Written by Chris Maunder (chrismaunder@codeguru.com)
// Copyright (c) 1998.
//
//	Drop edit stuff taken from "CDropEdit"
//	Copyright 1997 Chris Losinger
//
//	shortcut expansion code modified from :
//	CShortcut, 1996 Rob Warner
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. If 
// the source code in  this file is used in any commercial application 
// then acknowledgement must be made to the author of this file 
// (in whatever form you wish).
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage whatsoever.
//
// Expect bugs.
// 
// Please use and enjoy. Please let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into this
// file. 
//
// Modified: 12 Sep 1998 Setting correct cursor position after 
//                       auto-complete: Petr Stejskal and Ryan Schneider
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DropComboBox.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <afxdisp.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDropComboBox

CDropComboBox::CDropComboBox()
{
	m_bAutoComplete = TRUE;
	m_bAllowFiles   = TRUE;
    m_bAllowDirs    = TRUE;
    m_nMaxFiles     = 10;
    m_bNoRepeats    = TRUE;

    // Initialize OLE libraries
	m_bMustUninitOLE = FALSE;
    _AFX_THREAD_STATE* pState = AfxGetThreadState();
    if (!pState->m_bNeedTerm)
	{
		SCODE sc = ::OleInitialize(NULL);
		if (FAILED(sc))
            AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
		else
			m_bMustUninitOLE = TRUE;
	}
}

CDropComboBox::~CDropComboBox()
{
	// Uninitialize OLE support
	if (m_bMustUninitOLE)
		::OleUninitialize();
}


BEGIN_MESSAGE_MAP(CDropComboBox, CComboBox)
	//{{AFX_MSG_MAP(CDropComboBox)
	ON_CONTROL_REFLECT(CBN_EDITUPDATE, OnEditUpdate)
    ON_MESSAGE(CB_ADDSTRING, OnAddString)
    ON_MESSAGE(CB_INSERTSTRING, OnInsertString)
	ON_WM_CREATE()
	ON_WM_DROPFILES()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDropComboBox message handlers

BOOL CDropComboBox::PreTranslateMessage(MSG* pMsg)
{
	// Need to check for backspace/delete. These will modify the text in
	// the edit box, causing the auto complete to just add back the text
	// the user has just tried to delete. 

	if (pMsg->message == WM_KEYDOWN)
	{
		m_bAutoComplete = TRUE;

		int nVirtKey = (int) pMsg->wParam;
		if (nVirtKey == VK_DELETE || nVirtKey == VK_BACK)
			m_bAutoComplete = FALSE;
	}

	return CComboBox::PreTranslateMessage(pMsg);
}

LONG CDropComboBox::OnAddString(UINT /*wParam*/, LONG lParam)
{
    LPCTSTR lpszText = (LPCTSTR)lParam;

    int nIndex = CheckRepeats(lpszText);
    if (nIndex != CB_ERR)
        return nIndex;

    CheckOverflow();

    LONG lResult = Default();

    RecalcDropWidth();

    return lResult;
}

LONG CDropComboBox::OnInsertString(UINT /*wParam*/, LONG lParam)
{
    LPCTSTR lpszText = (LPCTSTR)lParam;

    int nIndex = CheckRepeats(lpszText);
    if (nIndex != CB_ERR)
        return nIndex;

    CheckOverflow();

    LONG lResult = Default();

    RecalcDropWidth();

    return lResult;
}

void CDropComboBox::OnEditUpdate() 
{
  // if we are not to auto update the text, get outta here
  if (!m_bAutoComplete) 
      return;

  // Get the text in the edit box
  CString str;
  GetWindowText(str);
  int nLength = str.GetLength();
  
  // Currently selected range
  DWORD dwCurSel = GetEditSel();
  WORD dStart = LOWORD(dwCurSel);
  WORD dEnd   = HIWORD(dwCurSel);

  // Search for, and select in, and string in the combo box that is prefixed
  // by the text in the edit box
  if (SelectString(-1, str) == CB_ERR)
  {
      SetWindowText(str);		// No text selected, so restore what was there before
      if (dwCurSel != CB_ERR)
        SetEditSel(dStart, dEnd);	//restore cursor postion
  }

  // Set the text selection as the additional text that we have added
  if (dEnd < nLength && dwCurSel != CB_ERR)
      SetEditSel(dStart, dEnd);
  else
      SetEditSel(nLength, -1);
}

int CDropComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CComboBox::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	DragAcceptFiles(TRUE);
	
	return 0;
}


//	handle WM_DROPFILES
//

void CDropComboBox::OnDropFiles(HDROP dropInfo)
{
	// Get the number of pathnames that have been dropped
	WORD wNumFilesDropped = DragQueryFile(dropInfo, -1, NULL, 0);

	CString firstFile="";

	// get all file names. but we'll only need the first one.
	for (WORD x = 0 ; x < wNumFilesDropped; x++) {

		// Get the number of bytes required by the file's full pathname
		WORD wPathnameSize = DragQueryFile(dropInfo, x, NULL, 0);

		// Allocate memory to contain full pathname & zero byte
		char * npszFile = (char *) LocalAlloc(LPTR, wPathnameSize += 1);

		// If not enough memory, skip this one
		if (npszFile == NULL) continue;

		// Copy the pathname into the buffer
		DragQueryFile(dropInfo, x, npszFile, wPathnameSize);

		// we only care about the first
		if (firstFile=="")
			firstFile=npszFile;

		// clean up
		LocalFree(npszFile);
	}

	// Free the memory block containing the dropped-file information
	DragFinish(dropInfo);

	// if this was a shortcut, we need to expand it to the target path
	CString expandedFile = ExpandShortcut(firstFile);

	// if that worked, we should have a real file name
	if (expandedFile!="") 
		firstFile=expandedFile;

	
	struct _stat buf;
	// get some info about that file
	int result = _stat( firstFile, &buf );
	if( result == 0 ) {

		// verify that we have a dir (if we want dirs)
		if ((buf.st_mode & _S_IFDIR) == _S_IFDIR) 
        {
			if (m_bAllowDirs)
				SetWindowText(firstFile);
            SetEditSel(firstFile.GetLength(), firstFile.GetLength());
		} 
		// verify that we have a file (if we want files)
        else if ((buf.st_mode & _S_IFREG) == _S_IFREG) 
        {
			if (m_bAllowFiles)
				SetWindowText(firstFile);
            SetEditSel(firstFile.GetLength(), firstFile.GetLength());
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
// CDropComboBox public functions

// inserts string at the top of the list of strings
void CDropComboBox::PushString(LPCTSTR szText)
{
    CString str;
    CStringArray aStrings;
    aStrings.Add(szText);

    int nNumStrings = GetCount();
    for (int i = 0; i < nNumStrings; i++)
    {
        GetLBText(i, str);
        if (m_bNoRepeats && str != szText)
            aStrings.Add(str);
    }
    ResetContent();
    nNumStrings = min(aStrings.GetSize(), m_nMaxFiles);

    for (i = 0; i < nNumStrings; i++)
    {
        AddString(aStrings[i]);
    }
}

/////////////////////////////////////////////////////////////////////////////
// CDropComboBox implementation

LONG CDropComboBox::CheckRepeats(LPCTSTR lpszText)
{
    if (!m_bNoRepeats)
        return CB_ERR;

    return FindString(-1, lpszText);
}

void CDropComboBox::CheckOverflow()
{
    if (m_nMaxFiles > 0 && GetCount() >= m_nMaxFiles)
        DeleteString(m_nMaxFiles-1);
}

void CDropComboBox::RecalcDropWidth()
{
    // Reset the dropped width
    int nNumEntries = GetCount();
    int nWidth = 0;
    CString str;

    CClientDC dc(this);
    int nSave = dc.SaveDC();
    dc.SelectObject(GetFont());

    int nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);
    for (int i = 0; i < nNumEntries; i++)
    {
        GetLBText(i, str);
        int nLength = dc.GetTextExtent(str).cx + nScrollWidth;
        nWidth = max(nWidth, nLength);
    }

    dc.RestoreDC(nSave);
    SetDroppedWidth(nWidth);
}

/////////////////////////////////////////////////////////////////////////////
// CDropComboBox static public utility functions

int CDropComboBox::GetFileType(LPCTSTR szFile)
{
    ASSERT(szFile);

    if (!szFile)
        return 0;

	// if this was a shortcut, we need to expand it to the target path
	CString strFile = ExpandShortcut(szFile);
	if (strFile == "") 
		strFile = szFile;
	
	struct _stat buf;
	int result = _stat( strFile, &buf );
	if (result != 0) 
        return 0;

    return buf.st_mode;
}

BOOL CDropComboBox::IsDirectory(LPCTSTR szFile)
{
    return ((GetFileType(szFile) & _S_IFDIR) == _S_IFDIR);
}

BOOL CDropComboBox::IsFile(LPCTSTR szFile)
{
    return ((GetFileType(szFile) & _S_IFREG) == _S_IFREG);
}

BOOL CDropComboBox::Exist(LPCTSTR szFile)
{
    return (GetFileType(szFile) != 0);
}

//////////////////////////////////////////////////////////////////
//	use IShellLink to expand the shortcut
//	returns the expanded file, or "" on error
//
//	original code was part of CShortcut 
//	1996 by Rob Warner
//	rhwarner@southeast.net
//	http://users.southeast.net/~rhwarner

CString CDropComboBox::ExpandShortcut(LPCTSTR szFile)
{
	CString outFile = "";

    // Make sure we have a path
    ASSERT(szFile && *szFile);
    if (!szFile || !szFile[0])
        return outFile;

    IShellLink* psl;
    HRESULT hres;

    // Create instance for shell link
    hres = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
        IID_IShellLink, (LPVOID*) &psl);
    if (SUCCEEDED(hres))
    {
        // Get a pointer to the persist file interface
        IPersistFile* ppf;
        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*) &ppf);
        if (SUCCEEDED(hres))
        {
            // Make sure it's ANSI
            WORD wsz[MAX_PATH];
            ::MultiByteToWideChar(CP_ACP, 0, szFile, -1, wsz, MAX_PATH);

            // Load shortcut
            hres = ppf->Load(wsz, STGM_READ);
            if (SUCCEEDED(hres)) {
				WIN32_FIND_DATA wfd;
				// find the path from that
				HRESULT hres = psl->GetPath(outFile.GetBuffer(MAX_PATH), 
								MAX_PATH,
								&wfd, 
								SLGP_UNCPRIORITY);

				outFile.ReleaseBuffer();
            }
            ppf->Release();
        }
        psl->Release();
    }

	// if this fails, outFile == ""
    return outFile;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -