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

📄 paneldrag.cpp

📁 7z一个高压缩比的压缩程序源代码,重要的是里面的算法值得学习
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// PanelDrag.cpp

#include "StdAfx.h"

#include "Common/StringConvert.h"

#include "Windows/Memory.h"
#include "Windows/FileDir.h"
#include "Windows/Shell.h"

#include "../Common/ArchiveName.h"
#include "../Common/CompressCall.h"

#include "MessagesDialog.h"

#include "App.h"
#include "EnumFormatEtc.h"

using namespace NWindows;

#ifndef _UNICODE
extern bool g_IsNT;
#endif

static wchar_t *kTempDirPrefix = L"7zE";
static LPCTSTR kSvenZipSetFolderFormat = TEXT("7-Zip::SetTargetFolder");

////////////////////////////////////////////////////////

class CDataObject:
  public IDataObject,
  public CMyUnknownImp
{
private:
  FORMATETC m_Etc;
  UINT m_SetFolderFormat;

public:
  MY_UNKNOWN_IMP1_MT(IDataObject)

  STDMETHODIMP GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium);
  STDMETHODIMP GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium);
  STDMETHODIMP QueryGetData(LPFORMATETC pformatetc );

  STDMETHODIMP GetCanonicalFormatEtc ( LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut)
    { pformatetcOut->ptd = NULL; return ResultFromScode(E_NOTIMPL); }

  STDMETHODIMP SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release);
  STDMETHODIMP EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc);
  
  STDMETHODIMP DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */)
    { return OLE_E_ADVISENOTSUPPORTED; }
  STDMETHODIMP DUnadvise(DWORD /* dwConnection */) { return OLE_E_ADVISENOTSUPPORTED; }
  STDMETHODIMP EnumDAdvise( LPENUMSTATDATA * /* ppenumAdvise */) { return OLE_E_ADVISENOTSUPPORTED; }

  CDataObject();

  NMemory::CGlobal hGlobal;
  UString Path;
};

CDataObject::CDataObject()
{
  m_SetFolderFormat = RegisterClipboardFormat(kSvenZipSetFolderFormat);
  m_Etc.cfFormat = CF_HDROP;
  m_Etc.ptd = NULL;
  m_Etc.dwAspect = DVASPECT_CONTENT;
  m_Etc.lindex = -1;
  m_Etc.tymed = TYMED_HGLOBAL;
}

STDMETHODIMP CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL /* release */)
{
  if (etc->cfFormat == m_SetFolderFormat && etc->tymed == TYMED_HGLOBAL &&
      etc->dwAspect == DVASPECT_CONTENT && medium->tymed == TYMED_HGLOBAL)
  {
    Path.Empty();
    if (medium->hGlobal == 0)
      return S_OK;
    size_t size = GlobalSize(medium->hGlobal) / sizeof(wchar_t);
    const wchar_t *src = (const wchar_t *)GlobalLock(medium->hGlobal);
    if (src != 0)
    {
      for (size_t i = 0; i < size; i++)
      {
        wchar_t c = src[i];
        if (c == 0)
          break;
        Path += c;
      }
      GlobalUnlock(medium->hGlobal);
      return S_OK;
    }
  }
  return E_NOTIMPL;
}

static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal)
{
  SIZE_T size = GlobalSize(srcGlobal);
  const void *src = GlobalLock(srcGlobal);
  if (src == 0)
    return 0;
  HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size);
  if (destGlobal != 0)
  {
    void *dest = GlobalLock(destGlobal);
    if (dest == 0)
    {
      GlobalFree(destGlobal);
      destGlobal = 0;
    }
    else
    {
      memcpy(dest, src, size);
      GlobalUnlock(destGlobal);
    }
  }
  GlobalUnlock(srcGlobal);
  return destGlobal;
}

STDMETHODIMP CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium)
{
  RINOK(QueryGetData(etc));
  medium->tymed = m_Etc.tymed;
  medium->pUnkForRelease = 0;
  medium->hGlobal = DuplicateGlobalMem(hGlobal);
  if (medium->hGlobal == 0)
    return E_OUTOFMEMORY;
  return S_OK;
}

STDMETHODIMP CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */)
{
  // Seems Windows doesn't call it, so we will not implement it.
  return E_UNEXPECTED;
}


STDMETHODIMP CDataObject::QueryGetData(LPFORMATETC etc)
{
  if ((m_Etc.tymed & etc->tymed) &&
       m_Etc.cfFormat == etc->cfFormat &&
       m_Etc.dwAspect == etc->dwAspect)
    return S_OK;
  return DV_E_FORMATETC;
}

STDMETHODIMP CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc)
{
  if (direction != DATADIR_GET)
    return E_NOTIMPL;
  return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc);
}

////////////////////////////////////////////////////////

class CDropSource:
  public IDropSource,
  public CMyUnknownImp
{
  DWORD m_Effect;
public:
  MY_UNKNOWN_IMP1_MT(IDropSource)
  STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState);
  STDMETHOD(GiveFeedback)(DWORD effect);


  bool NeedExtract;
  CPanel *Panel;
  CRecordVector<UInt32> Indices;
  UString Folder;
  CDataObject *DataObjectSpec;
  CMyComPtr<IDataObject> DataObject;
  
  bool NeedPostCopy;
  HRESULT Result;
  UStringVector Messages;

  CDropSource(): NeedPostCopy(false), Panel(0), Result(S_OK), m_Effect(DROPEFFECT_NONE) {}
};

STDMETHODIMP CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState)
{
  if (escapePressed == TRUE)
    return DRAGDROP_S_CANCEL;
  if ((keyState & MK_LBUTTON) == 0)
  {
    if (m_Effect == DROPEFFECT_NONE)
      return DRAGDROP_S_CANCEL;
    Result = S_OK;
    bool needExtract = NeedExtract;
    // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed);
    if (!DataObjectSpec->Path.IsEmpty())
    {
      needExtract = false;
      NeedPostCopy = true;
    }
    if (needExtract)
    {
      Result = Panel->CopyTo(Indices, Folder,
          false, // moveMode,
          false, // showMessages
          &Messages);
      if (Result != S_OK || !Messages.IsEmpty())
        return DRAGDROP_S_CANCEL;
    }
    return DRAGDROP_S_DROP;
  }
  return S_OK;
}

STDMETHODIMP CDropSource::GiveFeedback(DWORD effect)
{
  m_Effect = effect;
  return DRAGDROP_S_USEDEFAULTCURSORS;
}

static bool CopyNamesToHGlobal(NMemory::CGlobal &hgDrop, const UStringVector &names)
{
  size_t totalLength = 1;

  #ifndef _UNICODE
  if (!g_IsNT)
  {
    AStringVector namesA;
    int i;
    for (i = 0; i < names.Size(); i++)
      namesA.Add(GetSystemString(names[i]));
    for (i = 0; i < names.Size(); i++)
      totalLength += namesA[i].Length() + 1;
    
    if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLength * sizeof(CHAR) + sizeof(DROPFILES)))
      return false;
    
    NMemory::CGlobalLock dropLock(hgDrop);
    DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer();
    if (dropFiles == 0)
      return false;
    dropFiles->fNC = FALSE;
    dropFiles->pt.x = 0;
    dropFiles->pt.y = 0;
    dropFiles->pFiles = sizeof(DROPFILES);
    dropFiles->fWide = FALSE;
    CHAR *p = (CHAR *)((BYTE *)dropFiles + sizeof(DROPFILES));
    for (i = 0; i < names.Size(); i++)
    {
      const AString &s = namesA[i];
      int fullLength = s.Length() + 1;
      MyStringCopy(p, (const char *)s);
      p += fullLength;
      totalLength -= fullLength;
    }
    *p = 0;
  }
  else
  #endif
  {
    int i;
    for (i = 0; i < names.Size(); i++)
      totalLength += names[i].Length() + 1;
    
    if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLength * sizeof(WCHAR) + sizeof(DROPFILES)))
      return false;
    
    NMemory::CGlobalLock dropLock(hgDrop);
    DROPFILES* dropFiles = (DROPFILES*)dropLock.GetPointer();
    if (dropFiles == 0)
      return false;
    dropFiles->fNC = FALSE;
    dropFiles->pt.x = 0;
    dropFiles->pt.y = 0;
    dropFiles->pFiles = sizeof(DROPFILES);
    dropFiles->fWide = TRUE;
    WCHAR *p = (WCHAR *)((BYTE *)dropFiles + sizeof(DROPFILES));
    for (i = 0; i < names.Size(); i++)
    {
      const UString &s = names[i];
      int fullLength = s.Length() + 1;
      MyStringCopy(p, (const WCHAR *)s);
      p += fullLength;
      totalLength -= fullLength;
    }
    *p = 0;
  }
  return true;
}

void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */)
{
  CPanel::CDisableTimerProcessing disableTimerProcessing2(*this);
  if (!DoesItSupportOperations())
    return;
  CRecordVector<UInt32> indices;
  GetOperatedItemIndices(indices);
  if (indices.Size() == 0)
    return;

  // CSelectedState selState;
  // SaveSelectedState(selState);

  UString dirPrefix;
  NFile::NDirectory::CTempDirectoryW tempDirectory;

  bool isFSFolder = IsFSFolder();
  if (isFSFolder)
    dirPrefix = _currentFolderPrefix;
  else
  {
    tempDirectory.Create(kTempDirPrefix);
    dirPrefix = tempDirectory.GetPath();
    NFile::NName::NormalizeDirPathPrefix(dirPrefix);
  }

  CDataObject *dataObjectSpec = new CDataObject;
  CMyComPtr<IDataObject> dataObject = dataObjectSpec;

  {
    UStringVector names;
    for (int i = 0; i < indices.Size(); i++)
    {
      UInt32 index = indices[i];
      UString s;
      if (isFSFolder)
        s = GetItemRelPath(index);
      else
        s = GetItemName(index);
      names.Add(dirPrefix + s);
    }
    if (!CopyNamesToHGlobal(dataObjectSpec->hGlobal, names))
      return;
  }

  CDropSource *dropSourceSpec = new CDropSource;
  CMyComPtr<IDropSource> dropSource = dropSourceSpec;
  dropSourceSpec->NeedExtract = !isFSFolder;
  dropSourceSpec->Panel = this;
  dropSourceSpec->Indices = indices;
  dropSourceSpec->Folder = dirPrefix;
  dropSourceSpec->DataObjectSpec = dataObjectSpec;
  dropSourceSpec->DataObject = dataObjectSpec;

  bool moveIsAllowed = isFSFolder;

  DWORD effectsOK = DROPEFFECT_COPY;
  if (moveIsAllowed)
    effectsOK |= DROPEFFECT_MOVE;
  DWORD effect;
  _panelCallback->DragBegin();
  HRESULT res = DoDragDrop(dataObject, dropSource, effectsOK, &effect);
  _panelCallback->DragEnd();
  bool canceled = (res == DRAGDROP_S_CANCEL);
  if (res == DRAGDROP_S_DROP)
  {
    res = dropSourceSpec->Result;
    if (dropSourceSpec->NeedPostCopy)
      if (!dataObjectSpec->Path.IsEmpty())
      {
        NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->Path);
        res = CopyTo(indices, dataObjectSpec->Path,
          (effect == DROPEFFECT_MOVE),// dropSourceSpec->MoveMode,
          false, // showErrorMessages
          &dropSourceSpec->Messages);
      }
    /*
    if (effect == DROPEFFECT_MOVE)
      RefreshListCtrl(selState);
    */
  }
  else
  {
    if (res != DRAGDROP_S_CANCEL && res != S_OK)
      MessageBoxError(res);
    res = dropSourceSpec->Result;
  }

  if (!dropSourceSpec->Messages.IsEmpty())
  {
    CMessagesDialog messagesDialog;
    messagesDialog.Messages = &dropSourceSpec->Messages;
    messagesDialog.Create((*this));
  }
  if (res != S_OK && res != E_ABORT)
    MessageBoxError(res);
  if (res == S_OK && dropSourceSpec->Messages.IsEmpty() && !canceled)
    KillSelection();
}

void CDropTarget::QueryGetData(IDataObject *dataObject)
{
  FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK);

}

static void MySetDropHighlighted(HWND hWnd, int index, bool enable)

⌨️ 快捷键说明

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