| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880 | //---------------------------------------------------------------------------#pragma hdrstop//---------------------------------------------------------------------------#ifndef STRICT#define STRICT#endif//---------------------------------------------------------------------------#define LENOF(x) ( (sizeof((x))) / (sizeof(*(x))))//---------------------------------------------------------------------------#include <initguid.h>#include <shlguid.h>#include <stdlib.h>#include <stdio.h>#pragma warn -inl#include <shlobj.h>#pragma warn .inl#include <olectl.h>#include <time.h>#include "DragExt.h"//---------------------------------------------------------------------------#ifdef __BORLANDC__#undef STDAPI#define STDAPI EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE#endif//---------------------------------------------------------------------------#define Debug(MSG) \  if (GLogOn) \  { \    DoDebug(__FUNC__, MSG); \  }//---------------------------------------------------------------------------#define DRAG_EXT_REG_KEY L"Software\\Martin Prikryl\\WinSCP 2\\DragExt"#define DRAG_EXT_NAME L"WinSCP Shell Extension"#define THREADING_MODEL L"Apartment"#define CLSID_SIZE 39//---------------------------------------------------------------------------class CShellExtClassFactory : public IClassFactory{public:  CShellExtClassFactory();  virtual ~CShellExtClassFactory();  // IUnknown members  STDMETHODIMP         QueryInterface(REFIID, LPVOID FAR*);  STDMETHODIMP_(ULONG) AddRef();  STDMETHODIMP_(ULONG) Release();  // IClassFactory members  STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*);  STDMETHODIMP LockServer(BOOL);protected:  unsigned long FReferenceCounter;};//---------------------------------------------------------------------------#ifdef _WIN64#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wpadded"#endif//---------------------------------------------------------------------------class CShellExt : public IShellExtInit, ICopyHook{public:  CShellExt();  virtual ~CShellExt();  // IUnknown members  STDMETHODIMP         QueryInterface(REFIID, LPVOID FAR*);  STDMETHODIMP_(ULONG) AddRef();  STDMETHODIMP_(ULONG) Release();  // IShellExtInit methods  STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);  // ICopyHook method  STDMETHODIMP_(UINT) CopyCallback(HWND Hwnd, UINT Func, UINT Flags,    LPCWSTR SrcFile, DWORD SrcAttribs, LPCWSTR DestFile, DWORD DestAttribs);protected:  unsigned long FReferenceCounter;  LPDATAOBJECT FDataObj;  HANDLE FMutex;  unsigned long FLastTicks;};//---------------------------------------------------------------------------#ifdef WIN64#pragma clang diagnostic pop#endif//---------------------------------------------------------------------------unsigned int GRefThisDll = 0;bool GEnabled = false;wchar_t GLogFile[MAX_PATH] = L"";bool GLogOn = false;FILE* GLogHandle = NULL;HANDLE GLogMutex;HINSTANCE GInstance;//---------------------------------------------------------------------------static void DoDebug(const char* Func, const wchar_t* Message){  if (GLogOn)  {    unsigned long WaitResult = WaitForSingleObject(GLogMutex, 1000);    if (WaitResult != WAIT_TIMEOUT)    {      try      {        if (GLogHandle == NULL)        {          if (wcslen(GLogFile) == 0)          {            GLogOn = false;          }          else          {            GLogHandle = _wfopen(GLogFile, L"at");            if (GLogHandle == NULL)            {              GLogOn = false;            }            else            {              setbuf(GLogHandle, NULL);              fwprintf(GLogHandle, L"----------------------------\n");            }          }        }        if (GLogOn)        {          SYSTEMTIME Time;          GetSystemTime(&Time);          // cannot use TEXT(__FUNC__) as that does not work in clang,          // where __FUCT__ behaves like a static variable          const size_t FuncLen = strlen(Func) + 1;          wchar_t* WideFunc = new wchar_t[FuncLen];          mbstowcs(WideFunc, Func, FuncLen);          fwprintf(GLogHandle, L"[%2d/%2d/%4d %2d:%02d:%02d.%03d][%04x] [%s] %s\n",            Time.wDay, Time.wMonth, Time.wYear, Time.wHour, Time.wMinute,            Time.wSecond, Time.wMilliseconds, GetCurrentThreadId(), WideFunc, Message);          delete[] WideFunc;        }      }      catch(...)      {      }      ReleaseMutex(GLogMutex);    }  }}//---------------------------------------------------------------------------static void LogVersion(HINSTANCE HInstance){  if (GLogOn)  {    wchar_t FileName[MAX_PATH];    if (GetModuleFileName(HInstance, FileName, LENOF(FileName)) > 0)    {      Debug(FileName);      unsigned long InfoHandle, Size;      Size = GetFileVersionInfoSize(FileName, &InfoHandle);      if (Size > 0)      {        void* Info;        Info = new wchar_t[Size];        if (GetFileVersionInfo(FileName, InfoHandle, Size, Info) != 0)        {          VS_FIXEDFILEINFO* VersionInfo;          unsigned int VersionInfoSize;          if (VerQueryValue(Info, L"\\", reinterpret_cast<void**>(&VersionInfo),                &VersionInfoSize) != 0)          {            wchar_t VersionStr[100];            snwprintf(VersionStr, LENOF(VersionStr), L"%d.%d.%d.%d",              HIWORD(VersionInfo->dwFileVersionMS),              LOWORD(VersionInfo->dwFileVersionMS),              HIWORD(VersionInfo->dwFileVersionLS),              LOWORD(VersionInfo->dwFileVersionLS));            Debug(VersionStr);          }          else          {            Debug(L"no fixed version info");          }        }        else        {          Debug(L"cannot read version info");        }      }      else      {        Debug(L"no version info");      }    }  }}//---------------------------------------------------------------------------extern "C" int APIENTRYDllMain(HINSTANCE HInstance, DWORD Reason, LPVOID /*Reserved*/){  if (Reason == DLL_PROCESS_ATTACH)  {    GInstance = HInstance;    if (GRefThisDll == 0)    {      GLogMutex = CreateMutex(NULL, false, DRAG_EXT_RUNNING_MUTEX);      for (int Root = 0; Root <= 1; Root++)      {        HKEY Key;        if (RegOpenKeyEx(Root == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,              DRAG_EXT_REG_KEY, 0,              STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,              &Key) == ERROR_SUCCESS)        {          unsigned long Type;          unsigned long Value;          unsigned long Size;          wchar_t Buf[MAX_PATH];          Size = sizeof(Value);          if ((RegQueryValueEx(Key, L"Enable", NULL, &Type,                 reinterpret_cast<unsigned char*>(&Value), &Size) == ERROR_SUCCESS) &&              (Type == REG_DWORD))          {            GEnabled = (Value != 0);          }          Size = sizeof(Buf);          if ((RegQueryValueEx(Key, L"LogFile", NULL, &Type,                 reinterpret_cast<unsigned char*>(&Buf), &Size) == ERROR_SUCCESS) &&              (Type == REG_SZ))          {            wcsncpy(GLogFile, Buf, LENOF(GLogFile));            GLogFile[LENOF(GLogFile) - 1] = L'\0';            GLogOn = true;          }          RegCloseKey(Key);        }      }      if (GLogOn)      {        Debug(L"loaded settings");        Debug(GEnabled ? L"enabled" : L"disabled");        #ifdef UNICODE        Debug(L"Unicode");        #else        Debug(L"Ansi");        #endif        #ifdef _WIN64        Debug(L"Win64");        #else        Debug(L"Win32");        #endif        LogVersion(HInstance);        TDragExtCommStruct CommStruct;        const char * CommStructPtr = reinterpret_cast<const char *>(&CommStruct);        wchar_t Buf[1024];        swprintf(Buf, L"Comm struct layout - Size %d - Version @%d + %d - Dragging @%d + %d - DropDest @%d + %d",          sizeof(CommStruct), reinterpret_cast<const char *>(&CommStruct.Version) - CommStructPtr, sizeof(CommStruct.Version),          reinterpret_cast<const char *>(&CommStruct.Dragging) - CommStructPtr, sizeof(CommStruct.Dragging),          reinterpret_cast<const char *>(&CommStruct.DropDest) - CommStructPtr, sizeof(CommStruct.DropDest));        Debug(Buf);      }    }    else    {      Debug(L"settings already loaded");    }    Debug(L"attach leave");  }  else if (Reason == DLL_PROCESS_DETACH)  {    Debug(L"detach enter");    CloseHandle(GLogMutex);  }  return 1;   // ok}//---------------------------------------------------------------------------STDAPI DllCanUnloadNow(void){  bool CanUnload = (GRefThisDll == 0);  Debug(CanUnload ? L"can" : L"cannot");  return (CanUnload ? S_OK : S_FALSE);}//---------------------------------------------------------------------------STDAPI DllGetClassObject(REFCLSID Rclsid, REFIID Riid, LPVOID* PpvOut){  Debug(L"enter");  *PpvOut = NULL;  if (IsEqualIID(Rclsid, CLSID_ShellExtension))  {    Debug(L"is ShellExtension");    CShellExtClassFactory* Pcf = new CShellExtClassFactory;    return Pcf->QueryInterface(Riid, PpvOut);  }  return CLASS_E_CLASSNOTAVAILABLE;}//---------------------------------------------------------------------------static bool RegisterServer(bool AllUsers){  Debug(L"enter");  Debug(AllUsers ? L"all users" : L"current users");  bool Result = false;  HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;  HKEY HKey;  DWORD Unused;  wchar_t ClassID[CLSID_SIZE];  StringFromGUID2(CLSID_ShellExtension, ClassID, LENOF(ClassID));  if ((RegOpenKeyEx(RootKey, L"Software\\Classes", 0, KEY_WRITE, &HKey) ==         ERROR_SUCCESS) &&      (RegCreateKeyEx(HKey, L"CLSID", 0, NULL,         REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey, &Unused) ==           ERROR_SUCCESS))  {    Debug(L"CLSID created");    if (RegCreateKey(HKey, ClassID, &HKey) == ERROR_SUCCESS)    {      Debug(L"class ID created");      RegSetValueEx(HKey, NULL, 0, REG_SZ,        reinterpret_cast<const unsigned char*>(DRAG_EXT_NAME), sizeof(DRAG_EXT_NAME));      if (RegCreateKey(HKey, L"InProcServer32", &HKey) == ERROR_SUCCESS)      {        Debug(L"InProcServer32 created");        wchar_t Filename[MAX_PATH];        GetModuleFileName(GInstance, Filename, LENOF(Filename));        RegSetValueEx(HKey, NULL, 0, REG_SZ,          reinterpret_cast<unsigned char*>(Filename), (wcslen(Filename) + 1) * sizeof(wchar_t));        RegSetValueEx(HKey, L"ThreadingModel", 0, REG_SZ,          reinterpret_cast<const unsigned char*>(THREADING_MODEL),          sizeof(THREADING_MODEL));      }    }    RegCloseKey(HKey);    if ((RegOpenKeyEx(RootKey, L"Software\\Classes",           0, KEY_WRITE, &HKey) == ERROR_SUCCESS) &&        (RegCreateKeyEx(HKey,           L"directory\\shellex\\CopyHookHandlers\\WinSCPCopyHook",           0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,           &Unused) == ERROR_SUCCESS))    {      Debug(L"WinSCPCopyHook created");      RegSetValueEx(HKey, NULL, 0, REG_SZ,        reinterpret_cast<unsigned char*>(ClassID), (wcslen(ClassID) + 1) * sizeof(wchar_t));      RegCloseKey(HKey);      if ((RegCreateKeyEx(RootKey, DRAG_EXT_REG_KEY,             0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &HKey,             &Unused) == ERROR_SUCCESS))      {        Debug(L"drag ext key created");        unsigned long Value = 1;        RegSetValueEx(HKey, L"Enable", 0, REG_DWORD,          reinterpret_cast<unsigned char*>(&Value), sizeof(Value));        RegCloseKey(HKey);        Result = true;      }      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);    }  }  Debug(L"leave");  return Result;}//---------------------------------------------------------------------------STDAPI DllRegisterServer(){  Debug(L"enter");  HRESULT Result;  if (RegisterServer(true) || RegisterServer(false))  {    Result = S_OK;  }  else  {    Result = SELFREG_E_CLASS;  }  Debug(L"leave");  return Result;}//---------------------------------------------------------------------------static bool UnregisterServer(bool AllUsers){  Debug(L"enter");  Debug(AllUsers ? L"all users" : L"current users");  bool Result = false;  wchar_t ClassID[CLSID_SIZE];  StringFromGUID2(CLSID_ShellExtension, ClassID, LENOF(ClassID));  HKEY RootKey = AllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;  HKEY HKey;  if ((RegOpenKeyEx(RootKey, L"Software\\Classes", 0, KEY_WRITE, &HKey) ==        ERROR_SUCCESS) &&      (RegOpenKeyEx(HKey, L"directory\\shellex\\CopyHookHandlers",        0, KEY_WRITE, &HKey) == ERROR_SUCCESS))  {    RegDeleteKey(HKey, L"WinSCPCopyHook");    RegCloseKey(HKey);  }  if ((RegOpenKeyEx(RootKey, L"Software\\Classes", 0, KEY_WRITE, &HKey) ==        ERROR_SUCCESS) &&      (RegOpenKeyEx(HKey, L"CLSID", 0, KEY_WRITE, &HKey) ==        ERROR_SUCCESS))  {    if (RegOpenKeyEx(HKey, ClassID, 0, KEY_WRITE, &HKey) == ERROR_SUCCESS)    {      RegDeleteKey(HKey, L"InProcServer32");      RegCloseKey(HKey);      if ((RegOpenKeyEx(RootKey, L"Software\\Classes", 0, KEY_WRITE, &HKey) ==             ERROR_SUCCESS) &&          (RegOpenKeyEx(HKey, L"CLSID", 0, KEY_WRITE, &HKey) ==             ERROR_SUCCESS))      {        RegDeleteKey(HKey, ClassID);        RegCloseKey(HKey);        Result = true;      }    }  }  if (RegOpenKeyEx(RootKey, DRAG_EXT_REG_KEY, 0, KEY_WRITE, &HKey) ==        ERROR_SUCCESS)  {    // Previously we were setting the value explicitly to 0,    // but doing that for both HKLM and HKCU.    // While on register, we set it to 1 for HKLM only,    // what makes the extension disabled effectivelly,    // as KHCU value 0, is kept even after re-registration    RegDeleteValue(HKey, L"Enable");    RegCloseKey(HKey);    Result = true;  }  SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0);  Debug(L"leave");  return Result;}//---------------------------------------------------------------------------STDAPI DllUnregisterServer(){  Debug(L"enter");  HRESULT Result = SELFREG_E_CLASS;  if (UnregisterServer(true))  {    Result = S_OK;  }  if (UnregisterServer(false))  {    Result = S_OK;  }  Debug(L"leave");  return Result;}//---------------------------------------------------------------------------CShellExtClassFactory::CShellExtClassFactory(){  Debug(L"enter");  FReferenceCounter = 0;  GRefThisDll++;}//---------------------------------------------------------------------------CShellExtClassFactory::~CShellExtClassFactory(){  Debug(L"enter");  GRefThisDll--;}//---------------------------------------------------------------------------STDMETHODIMP CShellExtClassFactory::QueryInterface(REFIID Riid, LPVOID FAR* Ppv){  Debug(L"enter");  *Ppv = NULL;  // Any interface on this object is the object pointer  if (IsEqualIID(Riid, IID_IUnknown) || IsEqualIID(Riid, IID_IClassFactory))  {    Debug(L"is IUnknown or IClassFactory");    *Ppv = (LPCLASSFACTORY)this;    AddRef();    return NOERROR;  }  return E_NOINTERFACE;}//---------------------------------------------------------------------------STDMETHODIMP_(ULONG) CShellExtClassFactory::AddRef(){  Debug(L"enter");  return ++FReferenceCounter;}//---------------------------------------------------------------------------STDMETHODIMP_(ULONG) CShellExtClassFactory::Release(){  Debug(L"enter");  if (--FReferenceCounter)  {    return FReferenceCounter;  }  delete this;  return 0;}//---------------------------------------------------------------------------STDMETHODIMP CShellExtClassFactory::CreateInstance(LPUNKNOWN UnkOuter,  REFIID Riid, LPVOID* PpvObj){  Debug(L"enter");  *PpvObj = NULL;  // Shell extensions typically don't support aggregation (inheritance)  if (UnkOuter)  {    return CLASS_E_NOAGGREGATION;  }  // Create the main shell extension object.  The shell will then call  // QueryInterface with IID_IShellExtInit--this is how shell extensions are  // initialized.  CShellExt* ShellExt = new CShellExt();  //Create the CShellExt object  return ShellExt->QueryInterface(Riid, PpvObj);}//---------------------------------------------------------------------------STDMETHODIMP CShellExtClassFactory::LockServer(BOOL /*Lock*/){  Debug(L"enter");  return NOERROR;}//---------------------------------------------------------------------------// CShellExtCShellExt::CShellExt(){  Debug(L"enter");  FReferenceCounter = 0L;  FDataObj = NULL;  FMutex = CreateMutex(NULL, false, DRAG_EXT_MUTEX);  FLastTicks = 0;  GRefThisDll++;  Debug(L"leave");}//---------------------------------------------------------------------------CShellExt::~CShellExt(){  Debug(L"enter");  if (FDataObj)  {    FDataObj->Release();  }  CloseHandle(FMutex);  GRefThisDll--;  Debug(L"leave");}//---------------------------------------------------------------------------STDMETHODIMP CShellExt::QueryInterface(REFIID Riid, LPVOID FAR* Ppv){  Debug(L"enter");  HRESULT Result = E_NOINTERFACE;  *Ppv = NULL;  if (!GEnabled)  {    Debug(L"shellext disabled");  }  else  {    if (IsEqualIID(Riid, IID_IShellExtInit) || IsEqualIID(Riid, IID_IUnknown))    {      Debug(L"is IShellExtInit or IUnknown");      *Ppv = (LPSHELLEXTINIT)this;    }    else if (IsEqualIID(Riid, IID_IShellCopyHook))    {      Debug(L"is IShellCopyHook");      *Ppv = (LPCOPYHOOK)this;    }    if (*Ppv)    {      AddRef();      Result = NOERROR;    }  }  Debug(L"leave");  return Result;}//---------------------------------------------------------------------------STDMETHODIMP_(ULONG) CShellExt::AddRef(){  Debug(L"enter");  return ++FReferenceCounter;}//---------------------------------------------------------------------------STDMETHODIMP_(ULONG) CShellExt::Release(){  Debug(L"enter");  if (--FReferenceCounter)  {    return FReferenceCounter;  }  delete this;  return 0;}//---------------------------------------------------------------------------STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST /*IDFolder*/,  LPDATAOBJECT DataObj, HKEY /*RegKey*/){  Debug(L"enter");  if (FDataObj != NULL)  {    FDataObj->Release();    FDataObj = NULL;  }  // duplicate the object pointer and registry handle  if (DataObj != NULL)  {    FDataObj = DataObj;    DataObj->AddRef();  }  Debug(L"leave");  return NOERROR;}//---------------------------------------------------------------------------STDMETHODIMP_(UINT) CShellExt::CopyCallback(HWND /*Hwnd*/, UINT Func, UINT /*Flags*/,  LPCWSTR SrcFile, DWORD /*SrcAttribs*/, LPCWSTR DestFile, DWORD /*DestAttribs*/){  Debug(L"enter");  UINT Result = IDYES;  if (GEnabled && ((Func == FO_COPY) || (Func == FO_MOVE)))  {    Debug(L"copy or move");    unsigned long Ticks = GetTickCount();    if (((Ticks - FLastTicks) >= 100) ||        (FLastTicks > Ticks))    {      Debug(L"interval elapsed");      Debug(L"source / dest:");      Debug(SrcFile);      Debug(DestFile);      FLastTicks = Ticks;      const wchar_t* BackPtr = wcsrchr(SrcFile, L'\\');      // WORKAROUND: Windows 10 1803 sends empty DestFile      if (wcslen(DestFile) == 0)      {        Debug(L"empty dest file");      }      else if ((BackPtr != NULL) &&          (wcsncmp(BackPtr + 1, DRAG_EXT_DUMMY_DIR_PREFIX,            DRAG_EXT_DUMMY_DIR_PREFIX_LEN) == 0))      {        Debug(L"filename has prefix");        HANDLE MapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,          false, DRAG_EXT_MAPPING);        if (MapFile != NULL)        {          Debug(L"mapfile found");          TDragExtCommStruct* CommStruct;          CommStruct = static_cast<TDragExtCommStruct*>(MapViewOfFile(MapFile,            FILE_MAP_ALL_ACCESS, 0, 0, 0));          if (CommStruct != NULL)          {            Debug(L"mapview created");            unsigned long WaitResult = WaitForSingleObject(FMutex, 1000);            if (WaitResult != WAIT_TIMEOUT)            {              Debug(L"mutex got");              if (CommStruct->Version >= TDragExtCommStruct::MinVersion)              {                Debug(L"supported structure version");                if (CommStruct->Dragging)                {                  Debug(L"dragging");                  Debug(CommStruct->DropDest);                  bool IsDropDest;                  if (_wcsicmp(CommStruct->DropDest, SrcFile) == 0)                  {                    IsDropDest = true;                    Debug(L"dragged file match as is");                  }                  else                  {                    wchar_t DropDestShort[MAX_PATH];                    wchar_t SrcFileShort[MAX_PATH];                    size_t DropDestSize = GetShortPathName(CommStruct->DropDest,                      DropDestShort, LENOF(DropDestShort));                    size_t SrcFileSize = GetShortPathName(SrcFile,                      SrcFileShort, LENOF(SrcFileShort));                    if ((DropDestSize == 0) || (SrcFileSize == 0))                    {                      Debug(L"cannot convert paths to short form");                      IsDropDest = false;                    }                    else if ((DropDestSize >= LENOF(DropDestShort)) ||                        (SrcFileSize >= LENOF(SrcFileShort)))                    {                      Debug(L"short paths too long");                      IsDropDest = false;                    }                    else                    {                      Debug(DropDestShort);                      Debug(SrcFileShort);                      if (_wcsicmp(DropDestShort, SrcFileShort) == 0)                      {                        Debug(L"dragged file match after converted to short form");                        IsDropDest = true;                      }                      else                      {                        Debug(L"dragged file does NOT match");                        IsDropDest = false;                      }                    }                  }                  if (IsDropDest)                  {                    CommStruct->Dragging = false;                    wcsncpy(CommStruct->DropDest, DestFile, LENOF(CommStruct->DropDest));                    CommStruct->DropDest[LENOF(CommStruct->DropDest)-1] = L'\0';                    Result = IDNO;                    Debug(L"dragging refused");                  }                }                else                {                  Debug(L"NOT dragging");                }              }              else              {                Debug(L"unsupported structure version");              }              ReleaseMutex(FMutex);              Debug(L"mutex released");            }            else            {              Debug(L"mutex timeout");            }            UnmapViewOfFile(CommStruct);          }          else          {            Debug(L"mapview NOT created");          }          CloseHandle(MapFile);        }        else        {          Debug(L"mapfile NOT found");        }      }      else      {        Debug(L"filename has NOT prefix");      }    }    else    {      Debug(L"interval NOT elapsed");    }  }  else  {    if (GLogOn)    {      if (!GEnabled)      {        Debug(L"disabled");      }      else      {        wchar_t Buf[1024];        swprintf(Buf, L"NOT copy nor move - %d", Func);        Debug(Buf);      }    }  }  Debug(L"leave");  return Result;}
 |