none
복사한 파일을 특정 폴더에 "붙여넣기(Paste)" 자동 수행 RRS feed

  • 질문

  • 임의의 파일을 CTRL+C를 눌러서 복사한 후,

    프로그램을 실행했을 때 Paste가 자동 수행되서 원하는 폴더(D드라이브 target 폴더)에 파일을 붙여넣기 하고 싶습니다.

    아래 코드처럼 작성해서 실행했을 때 "paste" 메뉴까지 잘 획득했으나,

    "paste"는 정상적으로 invokeCommand()로 수행되지 않네요.

    다른 메뉴(예:WinRAR_Add)는 제대로 실행이 되는데..

    어떻게 해야할까요?

    	HRESULT hr = S_FALSE;
    	IContextMenu *cm;
    	HWND hwnd = GetDesktopWindow();
    
    	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    
    	IShellFolder *desktopFolder;
    	// Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace.
    	SHGetDesktopFolder(&desktopFolder);
    
    	LPITEMIDLIST parentPidl;
    	DWORD eaten;
    	hr = desktopFolder->ParseDisplayName(hwnd, 0, L"D:\\target", &eaten, &parentPidl, 0);
    
    	IShellFolder *parentFolder;
    	LPCITEMIDLIST pidlChild;
    
    	hr = SHBindToParent(parentPidl, IID_IShellFolder, (void **)&parentFolder, &pidlChild);
    	hr = parentFolder->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST *)&pidlChild, IID_IContextMenu, NULL, (void **)&cm);
    
    	HMENU hmenu = CreatePopupMenu();
    	hr = cm->QueryContextMenu(hmenu, 0, 1, 0x7FFF, CMF_NORMAL); //|CMF_EXPLORE|CMF_EXTENDEDVERBS);
    
    	for(UINT_PTR i=0; i<0x7FFF;i++)
    	{
    		char szShortCut[MAX_PATH]={0};
    		hr = cm->GetCommandString(i, GCS_VERBA, NULL, szShortCut, (UINT)(sizeof(szShortCut)));
    		if( strlen(szShortCut) ) printf("i=%d,menu=%s\n", i, szShortCut);
    	}
    
    	CMINVOKECOMMANDINFOEX ci = {0};
    	const char *command = "paste";
    
    	ZeroMemory(&ci, sizeof(ci));
    	ci.cbSize = sizeof(ci);
    	ci.hwnd = hwnd;
    	ci.lpVerb = command;
    	ci.lpParameters = NULL;
    	ci.lpDirectory = NULL;
    	ci.nShow = SW_SHOWNORMAL;
    	hr = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ci);
    
    	DestroyMenu(hmenu);
    
    	CoUninitialize();

    2016년 8월 29일 월요일 오전 8:42

답변

  • 올리신 코드로 테스트해보니 저는 잘 수행이 되긴 합니다.

    InvokeCommand 의 반환값을 확인해보셔야 할 것 같습니다.

    제가 같은 기능을 구현한다면 아래와 같이 클립보드에 직접 접근하여 파일 목록을 얻어온 후 복사할 것 같네요.

    BOOL PasteCurrentClipboardFile(LPCTSTR lpszTargetDir)
    {
    	if (!::IsClipboardFormatAvailable(CF_HDROP))
    		return FALSE;
    
    	if (!::OpenClipboard(NULL))
    		return FALSE;
    	
    	BOOL bResult = FALSE;
    	HGLOBAL hGlobal = (HGLOBAL)::GetClipboardData(CF_HDROP);
    	if (hGlobal)
    	{
    		HDROP hDrop = (HDROP)::GlobalLock(hGlobal);
    		if (hDrop)
    		{			
    			int nCount = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
    			TCHAR* szFileNames = new TCHAR[MAX_PATH * nCount + 1];
    			int nPos = 0;
    			for (int i = 0; i < nCount; ++i)
    			{
    				nPos += ::DragQueryFile(hDrop, i, szFileNames + nPos, MAX_PATH + 1) + 1;
    			}
    			szFileNames[nPos] = 0;
    			
    			SHFILEOPSTRUCT fos = { 0 };
    			fos.wFunc = FO_COPY;
    			fos.fFlags = FOF_NO_UI | FOF_ALLOWUNDO;
    			fos.pFrom = szFileNames;
    			fos.pTo = lpszTargetDir;
    
    			::SHFileOperation(&fos);
    			::GlobalUnlock(hGlobal);
    			bResult = TRUE;
    		}
    	}
    	
    	::CloseClipboard();
    	return bResult;
    }
    PasteCurrentClipboardFile(_T("D:\\Target"));

    2016년 8월 30일 화요일 오전 1:43

모든 응답

  • 올리신 코드로 테스트해보니 저는 잘 수행이 되긴 합니다.

    InvokeCommand 의 반환값을 확인해보셔야 할 것 같습니다.

    제가 같은 기능을 구현한다면 아래와 같이 클립보드에 직접 접근하여 파일 목록을 얻어온 후 복사할 것 같네요.

    BOOL PasteCurrentClipboardFile(LPCTSTR lpszTargetDir)
    {
    	if (!::IsClipboardFormatAvailable(CF_HDROP))
    		return FALSE;
    
    	if (!::OpenClipboard(NULL))
    		return FALSE;
    	
    	BOOL bResult = FALSE;
    	HGLOBAL hGlobal = (HGLOBAL)::GetClipboardData(CF_HDROP);
    	if (hGlobal)
    	{
    		HDROP hDrop = (HDROP)::GlobalLock(hGlobal);
    		if (hDrop)
    		{			
    			int nCount = ::DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0);
    			TCHAR* szFileNames = new TCHAR[MAX_PATH * nCount + 1];
    			int nPos = 0;
    			for (int i = 0; i < nCount; ++i)
    			{
    				nPos += ::DragQueryFile(hDrop, i, szFileNames + nPos, MAX_PATH + 1) + 1;
    			}
    			szFileNames[nPos] = 0;
    			
    			SHFILEOPSTRUCT fos = { 0 };
    			fos.wFunc = FO_COPY;
    			fos.fFlags = FOF_NO_UI | FOF_ALLOWUNDO;
    			fos.pFrom = szFileNames;
    			fos.pTo = lpszTargetDir;
    
    			::SHFileOperation(&fos);
    			::GlobalUnlock(hGlobal);
    			bResult = TRUE;
    		}
    	}
    	
    	::CloseClipboard();
    	return bResult;
    }
    PasteCurrentClipboardFile(_T("D:\\Target"));

    2016년 8월 30일 화요일 오전 1:43
  • 제가 올린 글의 코드가 실행이 되나요..? 저는 아무리 해도 Target 폴더에 파일이 생성되지 않습니다.

    심지어 InvokeCommand 반환값도 0 입니다. GetLastError() 값도 0이구요.

    윈도우7 64비트 환경인데 혹시 테스트 환경이 어떻게 되시는지요..?

    더불어 보내주신 코드는 SHFileOperation을 이용해서 파일을 복사하는 기능이네요.

    제가 구현하려고 하는 Paste 경우는 원본 파일의 Full Path를 모른다는 가정이다 보니,

    SHFileOperation은 배제하고 구현하고 있습니다.

    감사합니다.

    2016년 8월 30일 화요일 오전 2:45
  • Windows 10 64bit 에서 테스트 해보았습니다.

    InvokeCommand 반환 값이 0이면 성공인데 이상하네요.

    그리고 제가 올려드린 코드는 클립보드 열어서 원본 파일의 경로를 구한 뒤 복사하는 것이기 때문에

    결과적으론 똑같습니다.

    2016년 8월 30일 화요일 오전 3:01
  • 네 맞습니다. 결과적으로는 동일합니다. 다만 저는 원본 파일의 경로를 얻는 행위 없이 저희가 일반적으로,

    폴더에서 마우스 우측 버튼을 누르고 "붙여넣기(paste)"를 누르는 행위를 순수하게(?) InvokeCommand()로

    구현해보고자 함입니다.

    더불어 혹시나 싶어 Windows 10 64bit 에서 테스트해봤는데 저는 여전히 실행이 안되네요.

    뭔가.. 저주가....

    답변 감사합니다.

    2016년 8월 30일 화요일 오전 3:37