본문으로 건너뛰기

MS윈도 파일또는 폴더를 휴지통으로 버리기

윈도에서 프로그래밍을 하다보면 파일을 바로 삭제하는게 아닌 휴지통으로 이동시켜야 하는 경우가 생깁니다. os.Remove 같은 메소드를 이용하여 파일자체를 영구 삭제하는거야 매우 편하지만 ..

사용자를 대상으로 배포할 프로그램을 만드는 경우에는 가능하면 사용자의 실수도 감안하여 바로 삭제하는게 아닌 휴지통으로 이동을 시켜야 할 경우가 생깁니다.

이는 Go언어가 아닌 MFC나 Win32 API를 가지고 개발을 하더라도 결국 MS에서 제공하는 시스템 함수를 가지고서 다뤄야 하는 문제라 ..

Shell32.dll 에서 필요한 함수를 Import해서 다뤄야 하는 문제입니다. C/C++ 개발에서야 워낙 흔히 찾을 수 있는 코드 입니다만 ..

Go언어로 포팅된 코드는 잘 없는 편이라 남겨 봅니다.

Go
package main

import (
	"syscall"
	"unsafe"
)

type SHFILEOPSTRUCT struct {
	hwnd                  uintptr // HWND         hwnd;
	wFunc                 uint32  // UINT         wFunc; – 32bit; win32 api after all…
	pFrom                 *uint16 // PCZZTSTR     pFrom; – double zero terminated string; 16bit char pointer??? (let's try this…)
	pTo                   *uint16 // PCZZTSTR     pTo;
	fFlags                uint16  // FILEOP_FLAGS fFlags; – typedef WORD FILEOP_FLAGS
	fAnyOperationsAborted bool    // BOOL         fAnyOperationsAborted;
	hNameMappings         uintptr // LPVOID       hNameMappings;
	lpszProgressTitle     *uint16 // PCTSTR       lpszProgressTitle; – also 16bit char pointer???
}

const (
	 = iota
	FO_MOVE
	FO_COPY
	FO_DELETE
	FO_RENAME
)

const (
	FOF_ALLOWUNDO = 0x0040
)

func moveToTrash(path string) error {
	// TODO: Investigate potential DLL preloading attacks
	shell32, err := syscall.LoadDLL("Shell32.dll")
	if err != nil {
		return err
	}

	defer syscall.FreeLibrary(shell32.Handle)

	shFileOperationW, err := syscall.GetProcAddress(shell32.Handle, "SHFileOperationW")
	if err != nil {
		return err
	}

	pFrom, err := syscall.UTF16PtrFromString(path)

	if err != nil {
		return err
	}

	fileOp := &SHFILEOPSTRUCT{
		wFunc:  FO_DELETE,
		pFrom:  pFrom, // *uint16 string
		fFlags: FOF_ALLOWUNDO,
	}

	, _, errno := syscall.Syscall(shFileOperationW, 1, uintptr(unsafe.Pointer(fileOp)), 0, 0)
	if errno != 0 {
		return errno
	}
	return nil
}