Thursday, January 13, 2011

Trashing Files: Part 3 (Windows)

In Part 1 and Part 2, we implemented send-to-trash on Mac OS and other Unix-like systems. In Part 3, we will be implementing support for the Windows Recycle Bin using Factor.

trash.windows

First, we create the trash.windows vocabulary:

USING: accessors alien.c-types alien.data alien.strings
alien.syntax classes.struct classes.struct.packed destructors
kernel io.encodings.utf16n libc math sequences system trash
windows.types ;

IN: trash.windows

We will be using the alien vocabulary to call the SHFileOperationW function from the shell32.dll library. Unfortunately, this function expects a "packed structure" (e.g., without data structure padding), so I needed to add support for this first (in the classes.struct.packed vocabulary). Using this, the PACKED-STRUCT: word creates a structure with each field aligned to a single byte.

LIBRARY: shell32

TYPEDEF: WORD FILEOP_FLAGS

PACKED-STRUCT: SHFILEOPSTRUCTW
    { hwnd HWND }
    { wFunc UINT }
    { pFrom LPCWSTR* }
    { pTo LPCWSTR* }
    { fFlags FILEOP_FLAGS }
    { fAnyOperationsAborted BOOL }
    { hNameMappings LPVOID }
    { lpszProgressTitle LPCWSTR } ;

FUNCTION: int SHFileOperationW ( SHFILEOPSTRUCTW* lpFileOp ) ;

CONSTANT: FO_DELETE HEX: 0003

CONSTANT: FOF_SILENT HEX: 0004
CONSTANT: FOF_NOCONFIRMATION HEX: 0010
CONSTANT: FOF_ALLOWUNDO HEX: 0040
CONSTANT: FOF_NOERRORUI HEX: 0400

With these defined, we can implement send-to-trash, by simply creating the SHFILEOPSTRUCTW structure (making sure to add extra null bytes to the end of the path being trashed -- since it should be "double null terminated"), and then performing the SHFileOperationW function.

M: windows send-to-trash ( path -- )
    [
        utf16n string>alien B{ 0 0 } append
        malloc-byte-array &free

        SHFILEOPSTRUCTW <struct>
            f >>hwnd
            FO_DELETE >>wFunc
            swap >>pFrom
            f >>pTo
            FOF_ALLOWUNDO
            FOF_NOCONFIRMATION bitor
            FOF_NOERRORUI bitor
            FOF_SILENT bitor >>fFlags

        SHFileOperationW [ throw ] unless-zero

    ] with-destructors ;

The code for this is on my Github.

No comments: