Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shell: Add SHFileOperationW #62

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Shell: Add SHFileOperationW #62

wants to merge 2 commits into from

Conversation

xoviat
Copy link

@xoviat xoviat commented Apr 1, 2019

Adds SHFileOperationW, which allows programs to use the windows recycle bin.

@zx2c4
Copy link
Contributor

zx2c4 commented May 4, 2019

Is there a corresponding lxn/walk commit for this? IIRC, this is a somewhat tricky interface to use because it requires creating double-null-terminated strings.

@xoviat
Copy link
Author

xoviat commented May 4, 2019

lxn/walk doesn't use this. However, I have implemented an example of this in the "use syscall mechanism on windows" linked above:

func getShortPathName(path string) (string, error) {
	p, err := syscall.UTF16FromString(path)
	if err != nil {
		return "", err
	}
	b := p // GetShortPathName says we can reuse buffer
	n := uint32(len(b))
	for {
		n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
		if err != nil {
			return "", err
		}
		if n <= uint32(len(b)) {
			return syscall.UTF16ToString(b[:n]), nil
		}
		b = make([]uint16, n)
	}
}

...
	filePath, err := getShortPathName(filePath)
	if err != nil {
		return "", err
	}

	fileop := win.SHFILEOPSTRUCT{
		Hwnd:                  win.HWND(0),
		WFunc:                 win.FO_DELETE,
		PFrom:                 syscall.StringToUTF16Ptr(filePath),
		PTo:                   nil,
		FFlags:                win.FOF_ALLOWUNDO | win.FOF_NOCONFIRMATION | win.FOF_NOERRORUI | win.FOF_SILENT,
		FAnyOperationsAborted: win.BOOL(0),
		HNameMappings:         0,
		LpszProgressTitle:     syscall.StringToUTF16Ptr(""),
	}

	result := win.SHFileOperation(&fileop)
	if result != 0 {
		return "", errors.New("File operation returned code " + strconv.Itoa(int(result)))
	}

@zx2c4
Copy link
Contributor

zx2c4 commented May 5, 2019

Why are you passing the short filename? Also, you're not doing the double null termination like msdn says you must. Perhaps you're just relying on the same-buffer-usage of your getShortFilePathName call? And then hoping the remaining bytes after the first null aren't real paths and somewhere in memory is two nulls?

@xoviat
Copy link
Author

xoviat commented May 5, 2019

You're correct that my initial implementation was less than optimal, but it passed the tests for random paths on my computer, so I assumed that it was good enough. You can see my revised implementation below. But regardless, the interface here is the same. Are you suggesting that changes be made to the lxn/win interface, or that an example is included in the comments? The reason that I proposed this here is that I try to share code across the entire ecosystem, and lxn/win seems to be the place to put windows apis.

func DoubleNullTerminatedUTF16PtrFromString(s string) *uint16 {
	return &(utf16.Encode([]rune(s + "\x00\x00"))[0])
}

func MoveToTrash(filePath string) (string, error) {
	if result := win.SHFileOperation(&win.SHFILEOPSTRUCT{
		Hwnd:                  win.HWND(0),
		WFunc:                 win.FO_DELETE,
		PFrom:                 DoubleNullTerminatedUTF16PtrFromString(filePath),
		PTo:                   nil,
		FFlags:                win.FOF_ALLOWUNDO | win.FOF_NOCONFIRMATION | win.FOF_NOERRORUI | win.FOF_SILENT,
		FAnyOperationsAborted: win.BOOL(0),
		HNameMappings:         0,
		LpszProgressTitle:     DoubleNullTerminatedUTF16PtrFromString(""), // Note: double-null termination not required
	}); result != 0 {
		return "", errors.New("File operation returned code " + strconv.Itoa(int(result)))
	}

	return "", nil
}

@xoviat
Copy link
Author

xoviat commented Aug 24, 2019

@lxn is there a way that I could get this merged?

@lxn
Copy link
Owner

lxn commented Aug 26, 2019

Please add yourself to the AUTHORS file.

@xoviat
Copy link
Author

xoviat commented Aug 29, 2019

@lxn Done.

@xoviat
Copy link
Author

xoviat commented Feb 15, 2020

@lxn Is there further action that you require?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants