From 501e894d039be1aea47b933f600828293f1d60ed Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Sat, 31 Aug 2013 17:05:17 +0000 Subject: [PATCH] - modified windows installer to register new shell ext dll for drag/drop. - stopped release shell ext dll from crashing by initializing ref counting members. - added logging to shell ext dll to debug crash. --- res/synergy.nsh | 8 + src/lib/synwinxt/CClassFactory.cpp | 34 +- src/lib/synwinxt/CDataHandlerExtension.cpp | 36 +- src/lib/synwinxt/synwinxt.cpp | 423 +++++++++++---------- 4 files changed, 294 insertions(+), 207 deletions(-) diff --git a/res/synergy.nsh b/res/synergy.nsh index ebf24582..f529ec9f 100644 --- a/res/synergy.nsh +++ b/res/synergy.nsh @@ -62,6 +62,7 @@ InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${product}" "" Delete "${dir}\launcher.exe" Delete "${dir}\synrgyhk.dll" Delete "${dir}\synwinhk.dll" + Delete "${dir}\synwinxt.dll" Delete "${dir}\libgcc_s_dw2-1.dll" Delete "${dir}\mingwm10.dll" Delete "${dir}\QtCore4.dll" @@ -162,6 +163,7 @@ Section "Server and Client" core File "${binDir}\Release\synergys.exe" File "${binDir}\Release\synergyc.exe" File "${binDir}\Release\synergyd.exe" + File "${binDir}\Release\synwinxt.dll" ; if the hook file exists, skip, assuming it couldn't be deleted ; because it was in use by some process. @@ -175,6 +177,9 @@ Section "Server and Client" core DetailPrint "Adding firewall exception" nsExec::ExecToStack "netsh firewall add allowedprogram $\"$INSTDIR\synergys.exe$\" Synergy ENABLE" + ; install the windows shell extension + ExecWait "regsvr32 /s $\"$INSTDIR\synwinxt.dll$\"" + ; install and run the service ExecWait "$INSTDIR\synergyd.exe /install" @@ -220,6 +225,9 @@ Section Uninstall ; delete all registry keys DeleteRegKey HKLM "SOFTWARE\${product}" DeleteRegKey HKLM "${controlPanelReg}\${product}" + + ; uninstall the windows shell extension + ExecWait "regsvr32 /s /u $\"$INSTDIR\synwinxt.dll$\"" ; note: edit macro to delete more files. !insertmacro DeleteFiles $INSTDIR diff --git a/src/lib/synwinxt/CClassFactory.cpp b/src/lib/synwinxt/CClassFactory.cpp index da50296b..633701ec 100644 --- a/src/lib/synwinxt/CClassFactory.cpp +++ b/src/lib/synwinxt/CClassFactory.cpp @@ -20,47 +20,64 @@ #include extern LONG g_refCount; +extern void outputDebugStringF(const char *str, ...); -CClassFactory::CClassFactory() +CClassFactory::CClassFactory() : + m_refCount(1) { + outputDebugStringF("synwinxt: > CClassFactory::ctor, g_refCount=%d", g_refCount); InterlockedIncrement(&g_refCount); + outputDebugStringF("synwinxt: < CClassFactory::ctor, g_refCount=%d", g_refCount); } CClassFactory::~CClassFactory() { + outputDebugStringF("synwinxt: > CClassFactory::dtor, g_refCount=%d", g_refCount); InterlockedDecrement(&g_refCount); + outputDebugStringF("synwinxt: < CClassFactory::dtor, g_refCount=%d", g_refCount); } HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface(REFIID riid, void **ppvObject) { + outputDebugStringF("synwinxt: > CClassFactory::QueryInterface"); static const QITAB qit[] = { QITABENT(CClassFactory, IClassFactory), { 0 }, }; - return QISearch(this, qit, riid, ppvObject); + HRESULT hr = QISearch(this, qit, riid, ppvObject); + + outputDebugStringF("synwinxt: < CClassFactory::QueryInterface, hr=%d", hr); + return hr; } ULONG STDMETHODCALLTYPE CClassFactory::AddRef() { - return InterlockedIncrement(&m_refCount); + outputDebugStringF("synwinxt: > CClassFactory::AddRef, m_refCount=%d", m_refCount); + LONG r = InterlockedIncrement(&m_refCount); + outputDebugStringF("synwinxt: < CClassFactory::AddRef, r=%d, m_refCount=%d", r, m_refCount); + return r; } ULONG STDMETHODCALLTYPE CClassFactory::Release() { - LONG count = InterlockedDecrement(&m_refCount); - if (count == 0) { + outputDebugStringF("synwinxt: > CClassFactory::Release, m_refCount=%d", m_refCount); + LONG r = InterlockedDecrement(&m_refCount); + if (r == 0) { delete this; } - return count; + + outputDebugStringF("synwinxt: < CClassFactory::Release, r=%d", r); + return r; } HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject) { + outputDebugStringF("synwinxt: > CClassFactory::CreateInstance"); if (pUnkOuter != NULL) { return CLASS_E_NOAGGREGATION; } @@ -70,18 +87,21 @@ CClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppvObject if (FAILED(hr)) { delete pExtension; } - + + outputDebugStringF("synwinxt: < CClassFactory::CreateInstance, hr=%d", hr); return hr; } HRESULT STDMETHODCALLTYPE CClassFactory::LockServer(BOOL fLock) { + outputDebugStringF("synwinxt: > CClassFactory::LockServer, g_refCount=%d", g_refCount); if (fLock) { InterlockedIncrement(&g_refCount); } else { InterlockedDecrement(&g_refCount); } + outputDebugStringF("synwinxt: < CClassFactory::LockServer, g_refCount=%d", g_refCount); return S_OK; } diff --git a/src/lib/synwinxt/CDataHandlerExtension.cpp b/src/lib/synwinxt/CDataHandlerExtension.cpp index 622eb07a..2d7cc76b 100644 --- a/src/lib/synwinxt/CDataHandlerExtension.cpp +++ b/src/lib/synwinxt/CDataHandlerExtension.cpp @@ -24,58 +24,82 @@ extern GUID g_CLSID; extern void updateDraggingDir(char*); extern void outputDebugStringF(const char *str, ...); -CDataHandlerExtension::CDataHandlerExtension() +CDataHandlerExtension::CDataHandlerExtension() : + m_refCount(1) { + outputDebugStringF("synwinxt: > CDataHandlerExtension::ctor, g_refCount=%d", g_refCount); InterlockedIncrement(&g_refCount); + outputDebugStringF("synwinxt: < CDataHandlerExtension::ctor, g_refCount=%d", g_refCount); } CDataHandlerExtension::~CDataHandlerExtension() { + outputDebugStringF("synwinxt: > CDataHandlerExtension::dtor, g_refCount=%d", g_refCount); InterlockedDecrement(&g_refCount); + outputDebugStringF("synwinxt: < CDataHandlerExtension::dtor, g_refCount=%d", g_refCount); } HRESULT STDMETHODCALLTYPE CDataHandlerExtension::QueryInterface(REFIID riid, void **ppvObject) { + outputDebugStringF("synwinxt: > CDataHandlerExtension::QueryInterface"); static const QITAB qit[] = { QITABENT(CDataHandlerExtension, IPersistFile), QITABENT(CDataHandlerExtension, IDataObject), { 0 }, }; - return QISearch(this, qit, riid, ppvObject); + HRESULT hr = QISearch(this, qit, riid, ppvObject); + + if (FAILED(hr)) { + outputDebugStringF("synwinxt: < CDataHandlerExtension::QueryInterface, hr=FAILED"); + } + else { + outputDebugStringF("synwinxt: < CDataHandlerExtension::QueryInterface, hr=%d", hr); + } + return hr; } ULONG STDMETHODCALLTYPE CDataHandlerExtension::AddRef() { - return InterlockedIncrement(&m_refCount); + outputDebugStringF("synwinxt: > CDataHandlerExtension::AddRef, m_refCount=%d", m_refCount); + LONG r = InterlockedIncrement(&m_refCount); + outputDebugStringF("synwinxt: < CDataHandlerExtension::AddRef, r=%d, m_refCount=%d", r, m_refCount); + return r; } ULONG STDMETHODCALLTYPE CDataHandlerExtension::Release() { - LONG count = InterlockedDecrement(&m_refCount); - if (count == 0) { + outputDebugStringF("synwinxt: > CDataHandlerExtension::Release, m_refCount=%d", m_refCount); + LONG r = InterlockedDecrement(&m_refCount); + if (r == 0) { delete this; } - return count; + outputDebugStringF("synwinxt: < CDataHandlerExtension::Release, r=%d", r); + return r; } HRESULT STDMETHODCALLTYPE CDataHandlerExtension::Load(__RPC__in LPCOLESTR pszFileName, DWORD dwMode) { + outputDebugStringF("synwinxt: > CDataHandlerExtension::Load"); + char selectedFileDir[MAX_PATH]; StringCchCopyW(m_selectedFileDir, ARRAYSIZE(m_selectedFileDir), pszFileName); WideCharToMultiByte(CP_ACP, 0, m_selectedFileDir, -1, selectedFileDir, MAX_PATH, NULL, NULL); updateDraggingDir(selectedFileDir); + outputDebugStringF("synwinxt: < CDataHandlerExtension::Load"); return S_OK; } HRESULT STDMETHODCALLTYPE CDataHandlerExtension::GetClassID(__RPC__out CLSID *pClassID) { + outputDebugStringF("synwinxt: > CDataHandlerExtension::GetClassID"); *pClassID = g_CLSID; + outputDebugStringF("synwinxt: < CDataHandlerExtension::GetClassID"); return S_OK; } diff --git a/src/lib/synwinxt/synwinxt.cpp b/src/lib/synwinxt/synwinxt.cpp index 12e164d2..9ae29bf0 100644 --- a/src/lib/synwinxt/synwinxt.cpp +++ b/src/lib/synwinxt/synwinxt.cpp @@ -43,199 +43,6 @@ HRESULT registerInprocServer(CHAR* module, const CLSID& clsid, CHAR* threadModel HRESULT registerShellExtDataHandler(CHAR* fileType, const CLSID& clsid); HRESULT unregisterShellExtDataHandler(CHAR* fileType, const CLSID& clsid); HRESULT unregisterInprocServer(const CLSID& clsid); -void outputDebugStringF(const char *str, ...); - -BOOL APIENTRY -DllMain(HMODULE module, DWORD reason, LPVOID reserved) -{ - switch (reason) { - case DLL_PROCESS_ATTACH: - g_instance = module; - DisableThreadLibraryCalls(module); - break; - - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - -STDAPI -DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppvObj) -{ - HRESULT hr = E_OUTOFMEMORY; - *ppvObj = NULL; - - CClassFactory *classFactory = new CClassFactory(); - if (classFactory != NULL) { - hr = classFactory->QueryInterface(riid, ppvObj); - classFactory->Release(); - } - return hr; -} - -STDAPI -DllCanUnloadNow() -{ - return g_refCount > 0 ? S_FALSE : S_OK; -} -STDAPI -DllRegisterServer() -{ - HRESULT hr; - - CHAR module[MAX_PATH]; - if (GetModuleFileName(g_instance, module, ARRAYSIZE(module)) == 0) { - hr = HRESULT_FROM_WIN32(GetLastError()); - return hr; - } - - // Register the component. - hr = registerInprocServer( - module, - g_CLSID, - "Apartment"); - - if (SUCCEEDED(hr)) { - hr = registerShellExtDataHandler( - "*", - g_CLSID); - } - - return hr; -} - -STDAPI -DllUnregisterServer() -{ - HRESULT hr = S_OK; - - CHAR module[MAX_PATH]; - if (GetModuleFileName(g_instance, module, ARRAYSIZE(module)) == 0) { - hr = HRESULT_FROM_WIN32(GetLastError()); - return hr; - } - - // Unregister the component. - hr = unregisterInprocServer(g_CLSID); - if (SUCCEEDED(hr)) { - // Unregister the context menu handler. - hr = unregisterShellExtDataHandler("*", g_CLSID); - } - - return hr; -} - -HRESULT -registerInprocServer(CHAR* module, const CLSID& clsid, CHAR* threadModel) -{ - if (module == NULL || threadModel == NULL) { - return E_INVALIDARG; - } - - HRESULT hr; - - WCHAR CLASSID[MAX_PATH]; - CHAR szCLSID[MAX_PATH]; - StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); - WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); - - CHAR subkey[MAX_PATH]; - - // Create the HKCR\CLSID\{}\InprocServer32 key. - hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "CLSID\\%s\\InprocServer32", szCLSID); - - if (SUCCEEDED(hr)) { - // Set the default value of the InprocServer32 key to the - // path of the COM module. - HKEY key = CArchMiscWindows::addKey(HKEY_CLASSES_ROOT, subkey); - CArchMiscWindows::setValue(key, NULL, module); - - if (SUCCEEDED(hr)) { - // Set the threading model of the component. - CArchMiscWindows::setValue(key, "ThreadingModel", threadModel); - } - } - - return hr; -} - -HRESULT -unregisterInprocServer(const CLSID& clsid) -{ - HRESULT hr = S_OK; - - WCHAR CLASSID[MAX_PATH]; - CHAR szCLSID[MAX_PATH]; - StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); - WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); - - CHAR subkey[MAX_PATH]; - - // Delete the HKCR\CLSID\{} key. - hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "CLSID\\%s", szCLSID); - if (SUCCEEDED(hr)) { - hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, subkey)); - } - - return hr; -} - -HRESULT -registerShellExtDataHandler(CHAR* fileType, const CLSID& clsid) -{ - if (fileType == NULL) { - return E_INVALIDARG; - } - - HRESULT hr; - - WCHAR szCLSID[MAX_PATH]; - CHAR CLASSID[MAX_PATH]; - StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); - WideCharToMultiByte(CP_ACP, 0, szCLSID, -1, CLASSID, MAX_PATH, NULL, NULL); - - CHAR subkey[MAX_PATH]; - - // Create the key HKCR\\shellex\DataHandler - hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "%s\\shellex\\DataHandler", fileType); - if (SUCCEEDED(hr)) { - // Set the default value of the key. - HKEY key = CArchMiscWindows::addKey(HKEY_CLASSES_ROOT, subkey); - CArchMiscWindows::setValue(key, NULL, CLASSID); - } - - return hr; -} - -HRESULT -unregisterShellExtDataHandler(CHAR* fileType, const CLSID& clsid) -{ - if (fileType == NULL) { - return E_INVALIDARG; - } - - HRESULT hr; - - WCHAR CLASSID[MAX_PATH]; - CHAR szCLSID[MAX_PATH]; - StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); - WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); - - CHAR subkey[MAX_PATH]; - - // Remove the HKCR\\shellex\DataHandler key. - hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "%s\\shellex\\DataHandler", fileType); - if (SUCCEEDED(hr)) { - hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, subkey)); - } - - return hr; -} void outputDebugStringF(const char* str, ...) @@ -249,15 +56,243 @@ outputDebugStringF(const char* str, ...) OutputDebugStringA(buf); } +BOOL APIENTRY +DllMain(HMODULE module, DWORD reason, LPVOID reserved) +{ + outputDebugStringF("synwinxt: > DllMain, reason=%d", reason); + + switch (reason) { + case DLL_PROCESS_ATTACH: + g_instance = module; + DisableThreadLibraryCalls(module); + break; + + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + } + + outputDebugStringF("synwinxt: < DllMain"); + return TRUE; +} + +STDAPI +DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppvObj) +{ + outputDebugStringF("synwinxt: > DllGetClassObject"); + + HRESULT hr = E_OUTOFMEMORY; + *ppvObj = NULL; + + CClassFactory *classFactory = new CClassFactory(); + if (classFactory != NULL) { + hr = classFactory->QueryInterface(riid, ppvObj); + classFactory->Release(); + } + + outputDebugStringF("synwinxt: < DllGetClassObject, hr=%d", hr); + return hr; +} + +STDAPI +DllCanUnloadNow() +{ + outputDebugStringF("synwinxt: > DllCanUnloadNow, g_refCount=%d", g_refCount); + int r = g_refCount > 0 ? S_FALSE : S_OK; + outputDebugStringF("synwinxt: < DllCanUnloadNow, g_refCount=%d, r=%d", g_refCount, r); + return r; +} +STDAPI +DllRegisterServer() +{ + outputDebugStringF("synwinxt: > DllRegisterServer"); + + HRESULT hr; + + CHAR module[MAX_PATH]; + if (GetModuleFileName(g_instance, module, ARRAYSIZE(module)) == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + outputDebugStringF("synwinxt: < DllRegisterServer, hr=%d", hr); + return hr; + } + + hr = registerInprocServer( + module, + g_CLSID, + "Apartment"); + + if (SUCCEEDED(hr)) { + hr = registerShellExtDataHandler( + "*", + g_CLSID); + } + + outputDebugStringF("synwinxt: < DllRegisterServer, hr=%d", hr); + return hr; +} + +STDAPI +DllUnregisterServer() +{ + outputDebugStringF("synwinxt: > DllUnregisterServer"); + + HRESULT hr = S_OK; + + CHAR module[MAX_PATH]; + if (GetModuleFileName(g_instance, module, ARRAYSIZE(module)) == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + outputDebugStringF("synwinxt: < DllRegisterServer, hr=%d", hr); + return hr; + } + + hr = unregisterInprocServer(g_CLSID); + if (SUCCEEDED(hr)) { + hr = unregisterShellExtDataHandler("*", g_CLSID); + } + + outputDebugStringF("synwinxt: < DllUnregisterServer, hr=%d", hr); + return hr; +} + +HRESULT +registerInprocServer(CHAR* module, const CLSID& clsid, CHAR* threadModel) +{ + outputDebugStringF("synwinxt: > registerInprocServer"); + + if (module == NULL || threadModel == NULL) { + return E_INVALIDARG; + } + + HRESULT hr; + + WCHAR CLASSID[MAX_PATH]; + CHAR szCLSID[MAX_PATH]; + StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); + WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); + + CHAR subkey[MAX_PATH]; + + // create the HKCR\CLSID\{}\InprocServer32 key. + hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "CLSID\\%s\\InprocServer32", szCLSID); + + if (SUCCEEDED(hr)) { + // set the default value of the InprocServer32 key to the + // path of the COM module. + HKEY key = CArchMiscWindows::addKey(HKEY_CLASSES_ROOT, subkey); + CArchMiscWindows::setValue(key, NULL, module); + + if (SUCCEEDED(hr)) { + // set the threading model of the component. + CArchMiscWindows::setValue(key, "ThreadingModel", threadModel); + } + } + + outputDebugStringF("synwinxt: < registerInprocServer, hr=%d", hr); + return hr; +} + +HRESULT +unregisterInprocServer(const CLSID& clsid) +{ + outputDebugStringF("synwinxt: > unregisterInprocServer"); + + HRESULT hr = S_OK; + + WCHAR CLASSID[MAX_PATH]; + CHAR szCLSID[MAX_PATH]; + StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); + WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); + + CHAR subkey[MAX_PATH]; + + // delete the HKCR\CLSID\{} key. + hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "CLSID\\%s", szCLSID); + if (SUCCEEDED(hr)) { + hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, subkey)); + } + + if (FAILED(hr)) { + outputDebugStringF("synwinxt: < unregisterInprocServer, hr=FAILED"); + } + else { + outputDebugStringF("synwinxt: < unregisterInprocServer, hr=%d", hr); + } + return hr; +} + +HRESULT +registerShellExtDataHandler(CHAR* fileType, const CLSID& clsid) +{ + outputDebugStringF("synwinxt: > registerShellExtDataHandler"); + + if (fileType == NULL) { + return E_INVALIDARG; + } + + HRESULT hr; + + WCHAR szCLSID[MAX_PATH]; + CHAR CLASSID[MAX_PATH]; + StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); + WideCharToMultiByte(CP_ACP, 0, szCLSID, -1, CLASSID, MAX_PATH, NULL, NULL); + + CHAR subkey[MAX_PATH]; + + // create the key HKCR\\shellex\DataHandler + hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "%s\\shellex\\DataHandler", fileType); + if (SUCCEEDED(hr)) { + // set the default value of the key. + HKEY key = CArchMiscWindows::addKey(HKEY_CLASSES_ROOT, subkey); + CArchMiscWindows::setValue(key, NULL, CLASSID); + } + + outputDebugStringF("synwinxt: < registerShellExtDataHandler, hr=%d", hr); + return hr; +} + +HRESULT +unregisterShellExtDataHandler(CHAR* fileType, const CLSID& clsid) +{ + outputDebugStringF("synwinxt: > unregisterShellExtDataHandler"); + + if (fileType == NULL) { + return E_INVALIDARG; + } + + HRESULT hr; + + WCHAR CLASSID[MAX_PATH]; + CHAR szCLSID[MAX_PATH]; + StringFromGUID2(clsid, CLASSID, ARRAYSIZE(CLASSID)); + WideCharToMultiByte(CP_ACP, 0, CLASSID, -1, szCLSID, MAX_PATH, NULL, NULL); + + CHAR subkey[MAX_PATH]; + + // remove the HKCR\\shellex\DataHandler key. + hr = StringCchPrintf(subkey, ARRAYSIZE(subkey), "%s\\shellex\\DataHandler", fileType); + if (SUCCEEDED(hr)) { + hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, subkey)); + } + + outputDebugStringF("synwinxt: < unregisterShellExtDataHandler, hr=%d", hr); + return hr; +} + void updateDraggingDir(char* dir) { + outputDebugStringF("synwinxt: > updateDraggingDir, dir=%s", dir); memcpy(g_draggingFileDir, dir, MAX_PATH); - outputDebugStringF("draggingFileDir: %s", g_draggingFileDir); + outputDebugStringF("synwinxt: < updateDraggingDir, g_draggingFileDir=%s", g_draggingFileDir); } void getDraggingFileDir(char* dir) { + outputDebugStringF("synwinxt: > getDraggingFileDir"); memcpy(dir, g_draggingFileDir, MAX_PATH); + outputDebugStringF("synwinxt: < getDraggingFileDir, dir=%s", dir); }