// Classic Shell (c) 2009-2017, Ivo Beltchev // Open-Shell (c) 2017-2018, The Open-Shell Team // Confidential information of Ivo Beltchev. Not for disclosure or distribution without prior written consent from the author #include "stdafx.h" #include #include #include #include #include #include "Translations.h" #include "Settings.h" #include "ResourceHelper.h" #include "ComHelper.h" #include "dllmain.h" static wchar_t g_TitleMove[256]; static wchar_t g_TitleCopy[256]; static wchar_t g_TitleFolder[256]; static wchar_t g_ButtonMove[256]; static wchar_t g_ButtonDontMove[256]; static wchar_t g_ButtonCopy[256]; static wchar_t g_ButtonDontCopy[256]; static wchar_t g_ButtonCancel[256]; static wchar_t g_ButtonMore[256]; static HMODULE g_hShell32; static void LogPrint( CString *pLog, const wchar_t *format, ... ) { wchar_t buf[256]; va_list args; va_start(args,format); int len=Vsprintf(buf,_countof(buf),format,args); va_end(args); *pLog+=buf; } // CClassicCopyFile - this is the implementation of the Copy UI dialog box for files class CClassicCopyFile { public: CClassicCopyFile( void ); ~CClassicCopyFile( void ); bool Run( HWND hWnd, IAccessible *pAcc, CString *pLog ); private: void EnumAccChildren( IAccessible *pAcc, CString *pLog ); void AddAccChild( IAccessible *pAcc, const VARIANT &id, CString *pLog ); void GetFileInfo( IAccessible *pAcc, bool bSrc ); CString m_FileName; bool m_bSystem; bool m_bReadOnly; HICON m_Icon; CString m_SrcSize; CString m_SrcTime; HICON m_SrcIcon; CString m_DstSize; CString m_DstTime; HICON m_DstIcon; typedef std::pair,int> CControl; CControl m_YesButton; CControl m_NoButton; CControl m_CheckBox; CControl m_Cancel; bool m_bCopyMultiLast; // the last of a series of multi-file boxes static INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ); static void PumpMessages( void ); }; CClassicCopyFile::CClassicCopyFile( void ) { m_Icon=m_SrcIcon=m_DstIcon=NULL; m_bCopyMultiLast=false; m_bSystem=m_bReadOnly=false; } CClassicCopyFile::~CClassicCopyFile( void ) { if (m_Icon) DestroyIcon(m_Icon); if (m_SrcIcon) DestroyIcon(m_SrcIcon); if (m_DstIcon) DestroyIcon(m_DstIcon); } // Show the dialog box. Returns true to suppress the original task dialog box bool CClassicCopyFile::Run( HWND hWnd, IAccessible *pAcc, CString *pLog ) { // find all interesting controls EnumAccChildren(pAcc,pLog); if (!m_YesButton.first || m_YesButton.second!=CHILDID_SELF || !m_NoButton.first || m_NoButton.second!=CHILDID_SELF || !m_Cancel.first) return false; // something is wrong, do nothing if (pLog) pLog->Empty(); // success - no need to log anything // get the info for the source and the destination file (file name, icon, properties) m_bReadOnly=false; m_bSystem=false; GetFileInfo(m_YesButton.first,true); GetFileInfo(m_NoButton.first,false); TlsData *pTlsData=GetTlsData(); if (m_CheckBox.first) pTlsData->bCopyMultiFile=true; else if (pTlsData->bCopyMultiFile) m_bCopyMultiLast=true; // pick the correct dialog template (for single and multiple files, for LTR and RTL) int dlg=pTlsData->bCopyMultiFile?(IsLanguageRTL()?IDD_FILEMULTIR:IDD_FILEMULTI):(IsLanguageRTL()?IDD_FILER:IDD_FILE); HWND parent=GetWindow(GetAncestor(hWnd,GA_ROOT),GW_OWNER); int res=(int)DialogBoxParam(g_Instance,MAKEINTRESOURCE(dlg),parent,DialogProc,(LPARAM)this); if (res==IDOK || (res==IDYES && m_bCopyMultiLast)) { // Yes was pressed, proceed with the operation m_YesButton.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); } else if (res==IDNO) { // No if (m_CheckBox.first && GetKeyState(VK_SHIFT)<0) m_CheckBox.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); // Shift+No = No to All PumpMessages(); // messages need to be pumped after every accessibility action. otherwise the next action doesn't work m_NoButton.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); } else if (res==IDYES) { // Yes to All m_CheckBox.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); PumpMessages(); // messages need to be pumped after every accessibility action. otherwise the next action doesn't work m_YesButton.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); } if (res==IDCANCEL) { // Cancel if (GetKeyState(VK_SHIFT)<0 || GetKeyState(VK_CONTROL)<0) return false; // // Shift+Cancel or Ctrl+Cancel was clicked - show the original dialog box m_Cancel.first->accDoDefaultAction(CComVariant(CHILDID_SELF)); } if (res==IDC_LINKMORE) { // More... was clicked - show the original dialog box return false; } return true; } void CClassicCopyFile::PumpMessages( void ) { MSG msg; while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } void CClassicCopyFile::AddAccChild( IAccessible *pAcc, const VARIANT &id, CString *pLog ) { CComVariant state; pAcc->get_accState(id,&state); if (state.intVal&(STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE)) return; CComVariant role; pAcc->get_accRole(id,&role); if (role.intVal==ROLE_SYSTEM_PUSHBUTTON) { CComBSTR name; if (SUCCEEDED(pAcc->get_accName(id,&name)) && name) { if (pLog) LogPrint(pLog,L"button found: '%s', %d\r\n",name,id.intVal); if (_wcsicmp(name,g_ButtonCopy)==0 || _wcsicmp(name,g_ButtonMove)==0) { m_YesButton.first=pAcc; m_YesButton.second=id.intVal; if (pLog) LogPrint(pLog,L"YES button: %p, %d\r\n",pAcc,id.intVal); } else if (_wcsicmp(name,g_ButtonDontCopy)==0 || _wcsicmp(name,g_ButtonDontMove)==0) { m_NoButton.first=pAcc; m_NoButton.second=id.intVal; if (pLog) LogPrint(pLog,L"NO button: %p, %d\r\n",pAcc,id.intVal); } else if (_wcsicmp(name,g_ButtonCancel)==0) { m_Cancel.first=pAcc; m_Cancel.second=id.intVal; if (pLog) LogPrint(pLog,L"CANCEL button: %p, %d\r\n",pAcc,id.intVal); } } } if (role.intVal==ROLE_SYSTEM_CHECKBUTTON) { // hopefully there is only one checkbox m_CheckBox.first=pAcc; m_CheckBox.second=id.intVal; } } void CClassicCopyFile::EnumAccChildren( IAccessible *pAcc, CString *pLog ) { AddAccChild(pAcc,CComVariant(CHILDID_SELF),pLog); long count; pAcc->get_accChildCount(&count); CComVariant children[20]; AccessibleChildren(pAcc,0,count,children,&count); for (int i=0;i pChild=children[i].pdispVal; if (pChild) EnumAccChildren(pChild,pLog); } else AddAccChild(pAcc,children[i],pLog); } } void CClassicCopyFile::GetFileInfo( IAccessible *pAcc, bool bSrc ) { long count; pAcc->get_accChildCount(&count); CComVariant children[20]; AccessibleChildren(pAcc,0,count,children,&count); wchar_t fname[_MAX_PATH]=L""; wchar_t dir[_MAX_PATH]=L""; CString size; CString date; // get the file name, directory, size and date for (int i=0;i pChild=children[i].pdispVal; if (pChild) pChild->get_accName(CComVariant(CHILDID_SELF),&name); } else { pAcc->get_accName(children[i],&name); } switch (i) { case 2: if (wcslen(name)<_countof(fname)) wcscpy_s(fname,name); break; case 3: if (wcslen(name)<_countof(dir)) wcscpy_s(dir,name); break; case 4: size=name; break; case 5: date=name; break; } } if (bSrc) { m_FileName=fname; m_SrcSize=size; m_SrcTime=date; } else { m_DstSize=size; m_DstTime=date; } if (!fname[0] || !dir[0]) return; wchar_t fname2[_MAX_PATH]; memcpy(fname2,fname,sizeof(fname2)); *PathFindExtension(fname2)=0; int len1=Strlen(fname2); // the directory text is something like "filename (directory)". we need to parse out the real directory name int len2=Strlen(dir); if (dir[0]==0x202A) len1++; // for Arabic the first character is some RTL marker. needs to be skipped if (dir[len1]==0x1E) len1++; // for Hebrew there is an extra control character after the file name if (len1+1>=len2 || dir[len1]!=L' ' || dir[len1+1]!=L'(' || dir[len2-1]!=L')') return; if (dir[len1+2]==0x202A) len1++; // for Hebrew the first character is some RTL marker. needs to be skipped if (dir[len2-2]==0x202C) len2--; // for Hebrew the last character is some RTL marker. needs to be skipped dir[len2-1]=0; // construct the full file name wchar_t path[_MAX_PATH]; _wmakepath_s(path,NULL,dir+len1+2,fname,NULL); if (!bSrc) { DWORD attrib=GetFileAttributes(path); if (attrib!=INVALID_FILE_ATTRIBUTES) { if (attrib&FILE_ATTRIBUTE_READONLY) m_bReadOnly=true; if (attrib&FILE_ATTRIBUTE_SYSTEM) m_bSystem=true; } } // get file icon HICON hIcon=NULL; CAbsolutePidl pidl; if (SUCCEEDED(SHParseDisplayName(path,NULL,&pidl,0,NULL)) && pidl) { int iconSize=GetSystemMetrics(SM_CXICON); HBITMAP hBitmap=NULL; CComPtr pFactory; if (SUCCEEDED(SHCreateItemFromIDList(pidl,IID_IShellItemImageFactory,(void**)&pFactory)) && pFactory) { SIZE size={iconSize,iconSize}; if (FAILED(pFactory->GetImage(size,SIIGBF_ICONONLY,&hBitmap))) hBitmap=NULL; } if (hBitmap) { HBITMAP hMonoBitmap=CreateBitmap(iconSize,iconSize,1,1,NULL); ICONINFO info={TRUE,0,0,hMonoBitmap,hBitmap}; hIcon=CreateIconIndirect(&info); DeleteObject(hMonoBitmap); DeleteObject(hBitmap); } } if (!hIcon) return; if (bSrc) m_SrcIcon=hIcon; else m_DstIcon=hIcon; } const int WM_BRINGFOREGROUND=WM_USER+11; INT_PTR CALLBACK CClassicCopyFile::DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg==WM_INITDIALOG) { SetWindowText(hwndDlg,FindTranslation(L"Copy.Title",L"Confirm File Replace")); CClassicCopyFile *pThis=(CClassicCopyFile*)lParam; wchar_t text[_MAX_PATH*2]; if (pThis->m_bSystem) { Sprintf(text,_countof(text),FindTranslation(L"Copy.SubtitleSys",L"This folder already contains a system file named '%s'."),pThis->m_FileName); if (GetSettingInt(L"OverwriteAlertLevel")>=1) PlaySound(L".Default",NULL,SND_APPLICATION|SND_ALIAS|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM); } else if (pThis->m_bReadOnly) { Sprintf(text,_countof(text),FindTranslation(L"Copy.SubtitleRO",L"This folder already contains a read-only file named '%s'."),pThis->m_FileName); if (GetSettingInt(L"OverwriteAlertLevel")>=2) PlaySound(L".Default",NULL,SND_APPLICATION|SND_ALIAS|SND_ASYNC|SND_NODEFAULT|SND_SYSTEM); } else Sprintf(text,_countof(text),FindTranslation(L"Copy.Subtitle",L"This folder already contains a file named '%s'."),pThis->m_FileName); SetDlgItemText(hwndDlg,IDC_STATICFNAME,text); // load icon for file conflict (146) from Shell32.dll HMODULE hShell32=GetModuleHandle(L"Shell32.dll"); pThis->m_Icon=LoadIcon(hShell32,MAKEINTRESOURCE(146)); if (pThis->m_Icon) SendDlgItemMessage(hwndDlg,IDC_STATICICON1,STM_SETICON,(LPARAM)pThis->m_Icon,0); // set the localized text SetDlgItemText(hwndDlg,IDC_STATICPROMPT1,FindTranslation(L"Copy.Prompt1",L"Do you want to replace the existing file:")); SetDlgItemText(hwndDlg,IDC_STATICDSTSIZE,pThis->m_DstSize); SetDlgItemText(hwndDlg,IDC_STATICDSTTIME,pThis->m_DstTime); SetDlgItemText(hwndDlg,IDC_STATICPROMPT2,FindTranslation(L"Copy.Prompt2",L"with this one?")); SendDlgItemMessage(hwndDlg,IDC_STATICDSTICON,STM_SETICON,(LPARAM)pThis->m_DstIcon,0); SetDlgItemText(hwndDlg,IDC_STATICSRCSIZE,pThis->m_SrcSize); SetDlgItemText(hwndDlg,IDC_STATICSRCTIME,pThis->m_SrcTime); SendDlgItemMessage(hwndDlg,IDC_STATICSRCICON,STM_SETICON,(LPARAM)pThis->m_SrcIcon,0); SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Copy.Yes",L"&Yes")); SetDlgItemText(hwndDlg,IDNO,FindTranslation(L"Copy.No",L"&No")); if (GetDlgItem(hwndDlg,IDYES)) SetDlgItemText(hwndDlg,IDYES,FindTranslation(L"Copy.YesAll",L"Yes to &All")); if (GetDlgItem(hwndDlg,IDCANCEL)) SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Copy.Cancel",L"Cancel")); Sprintf(text,_countof(text),L"%s",FindTranslation(L"Copy.More",L"&More...")); SetDlgItemText(hwndDlg,IDC_LINKMORE,text); PostMessage(hwndDlg,WM_BRINGFOREGROUND,0,0); return TRUE; } if (uMsg==WM_BRINGFOREGROUND) { // bring window to front (sometimes on Windows7 it shows up behind Explorer) SetForegroundWindow(hwndDlg); return TRUE; } if (uMsg==WM_COMMAND && (wParam==IDOK || wParam==IDYES || wParam==IDNO || wParam==IDCANCEL)) { EndDialog(hwndDlg,wParam); return TRUE; } if (uMsg==WM_NOTIFY) { NMHDR *pHdr=(NMHDR*)lParam; if (pHdr->idFrom==IDC_LINKMORE && (pHdr->code==NM_CLICK || pHdr->code==NM_RETURN)) { EndDialog(hwndDlg,IDC_LINKMORE); return TRUE; } } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // CClassicCopyFolder - this is the implementation of the Copy UI dialog box for folders class CClassicCopyFolder { public: CClassicCopyFolder( void ) { m_Icon=NULL; m_Original=NULL; } ~CClassicCopyFolder( void ); bool Run( HWND hWnd ); private: HICON m_Icon; HWND m_Original; static INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ); }; CClassicCopyFolder::~CClassicCopyFolder( void ) { if (m_Icon) DestroyIcon(m_Icon); } // Show the dialog box. Returns true to suppress the original task dialog box bool CClassicCopyFolder::Run( HWND hWnd ) { m_Original=hWnd; const int ID_ALLCHECK=16663; HWND check=GetDlgItem(hWnd,ID_ALLCHECK); bool bMulti=(check && (GetWindowLong(check,GWL_STYLE)&WS_VISIBLE)); // pick the correct dialog template (for single and multiple files, for LTR and RTL) int dlg=bMulti?(IsLanguageRTL()?IDD_FOLDERMULTIR:IDD_FOLDERMULTI):(IsLanguageRTL()?IDD_FOLDERR:IDD_FOLDER); HWND parent=GetWindow(GetAncestor(hWnd,GA_ROOT),GW_OWNER); int res=(int)DialogBoxParam(g_Instance,MAKEINTRESOURCE(dlg),parent,DialogProc,(LPARAM)this); if (res==IDOK) // Yes button for single folder { // Yes was pressed, proceed with the operation PostMessage(hWnd,WM_COMMAND,IDYES,(LPARAM)GetDlgItem(hWnd,IDYES)); } else if (res==IDNO) { // No if (bMulti) { if (GetKeyState(VK_SHIFT)<0) { CheckDlgButton(hWnd,ID_ALLCHECK,BST_CHECKED); SendMessage(hWnd,WM_COMMAND,ID_ALLCHECK,(LPARAM)check); } PostMessage(hWnd,WM_COMMAND,IDNO,(LPARAM)GetDlgItem(hWnd,IDNO)); // Skip } else PostMessage(hWnd,WM_COMMAND,IDCANCEL,(LPARAM)GetDlgItem(hWnd,IDCANCEL)); // No } else if (res==IDYES) { // Yes to All CheckDlgButton(hWnd,ID_ALLCHECK,BST_CHECKED); SendMessage(hWnd,WM_COMMAND,ID_ALLCHECK,(LPARAM)check); PostMessage(hWnd,WM_COMMAND,IDYES,(LPARAM)GetDlgItem(hWnd,IDYES)); } if (res==IDCANCEL) { // Cancel if (GetKeyState(VK_SHIFT)<0 || GetKeyState(VK_CONTROL)<0) return false; // // Shift+Cancel or Ctrl+Cancel was clicked - show the original dialog box PostMessage(hWnd,WM_COMMAND,IDCANCEL,(LPARAM)GetDlgItem(hWnd,IDCANCEL)); // No } if (res==IDC_LINKMORE) { // More... was clicked - show the original dialog box return false; } return true; } INT_PTR CALLBACK CClassicCopyFolder::DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg==WM_INITDIALOG) { SetWindowText(hwndDlg,FindTranslation(L"Folder.Title",L"Confirm Folder Replace")); CClassicCopyFolder *pThis=(CClassicCopyFolder*)lParam; wchar_t text[2048]; // find the link control and get its text HWND link=FindWindowEx(pThis->m_Original,NULL,WC_LINK,NULL); if (link) GetWindowText(link,text,_countof(text)); else text[0]=0; Strcat(text,_countof(text),L"\r\n\r\n"); Strcat(text,_countof(text),FindTranslation(L"Folder.Prompt",L"Do you still want to move or copy the folder?")); SetDlgItemText(hwndDlg,IDC_STATICFNAME,text); // load icon for file conflict (146) from Shell32.dll HMODULE hShell32=GetModuleHandle(L"Shell32.dll"); pThis->m_Icon=LoadIcon(hShell32,MAKEINTRESOURCE(146)); if (pThis->m_Icon) SendDlgItemMessage(hwndDlg,IDC_STATICICON1,STM_SETICON,(LPARAM)pThis->m_Icon,0); // set the localized text SetDlgItemText(hwndDlg,IDOK,FindTranslation(L"Copy.Yes",L"&Yes")); SetDlgItemText(hwndDlg,IDNO,FindTranslation(L"Copy.No",L"&No")); if (GetDlgItem(hwndDlg,IDYES)) SetDlgItemText(hwndDlg,IDYES,FindTranslation(L"Copy.YesAll",L"Yes to &All")); if (GetDlgItem(hwndDlg,IDCANCEL)) SetDlgItemText(hwndDlg,IDCANCEL,FindTranslation(L"Copy.Cancel",L"Cancel")); Sprintf(text,_countof(text),L"%s",FindTranslation(L"Copy.More",L"&More...")); SetDlgItemText(hwndDlg,IDC_LINKMORE,text); PostMessage(hwndDlg,WM_BRINGFOREGROUND,0,0); return TRUE; } if (uMsg==WM_BRINGFOREGROUND) { // bring window to front (sometimes on Windows7 it shows up behind Explorer) SetForegroundWindow(hwndDlg); return TRUE; } if (uMsg==WM_COMMAND && (wParam==IDOK || wParam==IDYES || wParam==IDNO || wParam==IDCANCEL)) { EndDialog(hwndDlg,wParam); return TRUE; } if (uMsg==WM_NOTIFY) { NMHDR *pHdr=(NMHDR*)lParam; if (pHdr->idFrom==IDC_LINKMORE && (pHdr->code==NM_CLICK || pHdr->code==NM_RETURN)) { EndDialog(hwndDlg,IDC_LINKMORE); return TRUE; } } return FALSE; } /////////////////////////////////////////////////////////////////////////////// static CComPtr FindMoreButton( IAccessible *pAcc ) { CComVariant state; CComVariant self(CHILDID_SELF); pAcc->get_accState(self,&state); if (!(state.intVal&(STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE))) { CComVariant role; pAcc->get_accRole(self,&role); if (role.intVal==ROLE_SYSTEM_PUSHBUTTON) { CComBSTR name; if (SUCCEEDED(pAcc->get_accName(self,&name)) && name && _wcsicmp(name,g_ButtonMore)==0) return pAcc; } } CComVariant children[30]; long count; AccessibleChildren(pAcc,0,_countof(children),children,&count); for (int i=0;i pChild=children[i].pdispVal; if (pChild) { CComPtr pRes=FindMoreButton(pChild); if (pRes) return pRes; } } } return NULL; } /////////////////////////////////////////////////////////////////////////////// static LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData ) { if (uMsg==WM_WINDOWPOSCHANGING) { WINDOWPOS *pos=(WINDOWPOS*)lParam; if (pos->flags&SWP_SHOWWINDOW) { wchar_t title[256]; GetWindowText(hWnd,title,_countof(title)); if (_wcsicmp(title,g_TitleMove)==0 || _wcsicmp(title,g_TitleCopy)==0) { // file UI if (GetSettingBool(L"ReplaceFileUI")) { CString log; CComPtr pAcc; HRESULT h=AccessibleObjectFromWindow(hWnd,OBJID_WINDOW,IID_IAccessible,(void**)&pAcc); if (SUCCEEDED(h) && pAcc) { CClassicCopyFile copy; if (copy.Run(hWnd,pAcc,g_bLogLevel?&log:NULL)) { pos->x=pos->y=-20000; pos->flags&=~(SWP_SHOWWINDOW|SWP_NOMOVE); } } else if (g_bLogLevel) LogPrint(&log,L"AccessibleObjectFromWindow: error=0x%X, hWnd=0x%p",h,hWnd); if (g_bLogLevel) { wchar_t fname[_MAX_PATH]=L"%LOCALAPPDATA%\\OpenShell"; DoEnvironmentSubst(fname,_MAX_PATH); SHCreateDirectory(NULL,fname); Strcat(fname,_countof(fname),L"\\ExplorerLog.txt"); if (!log.IsEmpty()) { FILE *f; if (_wfopen_s(&f,fname,L"wb")==0) { fwprintf(f,L"\xFEFF"); OSVERSIONINFOEX ver={sizeof(ver)}; #pragma warning(suppress:4996) GetVersionEx((OSVERSIONINFO*)&ver); fwprintf(f,L"version = %d.%d.%d - %d.%d\r\n\r\n",ver.dwMajorVersion,ver.dwMinorVersion,ver.dwBuildNumber,ver.wServicePackMajor,ver.wServicePackMinor); wchar_t languages[100]={0}; ULONG size=4; // up to 4 languages ULONG len=_countof(languages); GetUserPreferredUILanguages(MUI_LANGUAGE_NAME,&size,languages,&len); for (const wchar_t *lang=languages;*lang;lang+=wcslen(lang)+1) fwprintf(f,L"language = %s\r\n",lang); fwprintf(f,L"\r\n"); fwprintf(f,L"g_ButtonMove = '%s'\r\n",g_ButtonMove); fwprintf(f,L"g_ButtonDontMove = '%s'\r\n",g_ButtonDontMove); fwprintf(f,L"g_ButtonCopy = '%s'\r\n",g_ButtonCopy); fwprintf(f,L"g_ButtonDontCopy = '%s'\r\n",g_ButtonDontCopy); fwprintf(f,L"g_ButtonCancel = '%s'\r\n",g_ButtonCancel); fwprintf(f,L"\r\n"); fwrite((const wchar_t*)log,log.GetLength(),2,f); fclose(f); } } else DeleteFile(fname); } } } else if (_wcsicmp(title,g_TitleFolder)==0) { // folder UI if (GetSettingBool(L"ReplaceFolderUI")) { CClassicCopyFolder copy; if (copy.Run(hWnd)) { pos->x=pos->y=-20000; pos->flags&=~(SWP_SHOWWINDOW|SWP_NOMOVE); } } } else { // look for progress bar if (GetSettingBool(L"EnableMore")) { HWND progress=FindChildWindow(hWnd,PROGRESS_CLASS); if (progress) { bool bDef; int delay=GetSettingInt(L"MoreProgressDelay",bDef); if (bDef) { delay=0; if (GetWinVersion()>=WIN_VER_WIN7) { BOOL comp; if (SUCCEEDED(DwmIsCompositionEnabled(&comp)) && comp) delay=500; } } SetTimer(hWnd,'CLEX',delay,NULL); return DefSubclassProc(hWnd,uMsg,wParam,lParam); } } } LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); RemoveWindowSubclass(hWnd,WindowProc,uIdSubclass); return res; } } if (uMsg==WM_TIMER && wParam=='CLEX') { KillTimer(hWnd,wParam); CComPtr pAcc; HRESULT h=AccessibleObjectFromWindow(hWnd,OBJID_WINDOW,IID_IAccessible,(void**)&pAcc); if (SUCCEEDED(h) && pAcc) { CComPtr pMore=FindMoreButton(pAcc); if (pMore) pMore->accDoDefaultAction(CComVariant(CHILDID_SELF)); } LRESULT res=DefSubclassProc(hWnd,uMsg,wParam,lParam); RemoveWindowSubclass(hWnd,WindowProc,uIdSubclass); return res; } return DefSubclassProc(hWnd,uMsg,wParam,lParam); } LRESULT CALLBACK ClassicCopyHook( int nCode, WPARAM wParam, LPARAM lParam ) { if (nCode==HCBT_CREATEWND) { HWND hWnd=(HWND)wParam; CBT_CREATEWND *create=(CBT_CREATEWND*)lParam; HINSTANCE hInst=(HINSTANCE)GetWindowLongPtr(hWnd,GWLP_HINSTANCE); if (create->lpcs->lpszName && (intptr_t)create->lpcs->lpszClass==32770 && hInst==g_hShell32) { WaitDllInitThread(); static LONG id; int i=InterlockedIncrement(&id); SetWindowSubclass(hWnd,WindowProc,i,0); } } TlsData *pTlsData=GetTlsData(); return CallNextHookEx(pTlsData->copyHook,nCode,wParam,lParam); } void InitClassicCopyProcess( void ) { // load UI text from shell32.dll // the text is used to locate controls in the copy dialog by name g_hShell32=GetModuleHandle(L"shell32.dll"); LoadString(g_hShell32,17027,g_TitleMove,256); LoadString(g_hShell32,17024,g_TitleCopy,256); LoadString(g_hShell32,16705,g_TitleFolder,256); LoadString(g_hShell32,13610,g_ButtonMove,256); LoadString(g_hShell32,13623,g_ButtonDontMove,256); LoadString(g_hShell32,13604,g_ButtonCopy,256); LoadString(g_hShell32,13606,g_ButtonDontCopy,256); LoadString(g_hShell32,13588,g_ButtonCancel,256); LoadString(g_hShell32,32992,g_ButtonMore,256); } void InitClassicCopyThread( void ) { TlsData *pTlsData=GetTlsData(); if (!pTlsData->copyHook) pTlsData->copyHook=SetWindowsHookEx(WH_CBT,ClassicCopyHook,g_Instance,GetCurrentThreadId()); } void FreeClassicCopyThread( void ) { TlsData *pTlsData=GetTlsData(); if (pTlsData->copyHook) { UnhookWindowsHookEx(pTlsData->copyHook); pTlsData->copyHook=NULL; } }