Last active
December 18, 2015 12:59
-
-
Save juntalis/5786687 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local ffi = require('ffi') | |
| local rpcrt4 = ffi.load('rpcrt4') | |
| local ole32 = ffi.load('ole32') | |
| local shell32 = ffi.load('shell32') | |
| CLSCTX_INPROC_SERVER = 0x01 | |
| CLSCTX_INPROC_HANDLER = 0x02 | |
| CLSCTX_LOCAL_SERVER = 0x04 | |
| CLSCTX_INPROC_SERVER16 = 0x08 | |
| CLSCTX_REMOTE_SERVER = 0x10 | |
| CLSCTX_INPROC_HANDLER16 = 0x20 | |
| CLSCTX_NO_CODE_DOWNLOAD = 0x400 | |
| CLSCTX_RESERVED5 = 0x800 | |
| CLSCTX_NO_CUSTOM_MARSHAL = 0x1000 | |
| CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000 | |
| CLSCTX_NO_FAILURE_LOG = 0x4000 | |
| CLSCTX_DISABLE_AAA = 0x8000 | |
| CLSCTX_ENABLE_AAA = 0x10000 | |
| CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000 | |
| CLSCTX_ACTIVATE_32_BIT_SERVER = 0x40000 | |
| CLSCTX_ACTIVATE_64_BIT_SERVER = 0x80000 | |
| CLSCTX_ENABLE_CLOAKING = 0x100000 | |
| CLSCTX_ACTIVATE_SBX_SANDBOX = 0x200000 | |
| CLSCTX_PS_DLL = 0x80000000 | |
| FOS_OVERWRITEPROMPT = 0x00000002 | |
| FOS_STRICTFILETYPES = 0x00000004 | |
| FOS_NOCHANGEDIR = 0x00000008 | |
| FOS_PICKFOLDERS = 0x00000020 | |
| FOS_FORCEFILESYSTEM = 0x00000040 | |
| FOS_ALLNONSTORAGEITEMS = 0x00000080 | |
| FOS_NOVALIDATE = 0x00000100 | |
| FOS_ALLOWMULTISELECT = 0x00000200 | |
| FOS_PATHMUSTEXIST = 0x00000800 | |
| FOS_FILEMUSTEXIST = 0x00001000 | |
| FOS_CREATEPROMPT = 0x00002000 | |
| FOS_SHAREAWARE = 0x00004000 | |
| FOS_NOREADONLYRETURN = 0x00008000 | |
| FOS_NOTESTFILECREATE = 0x00010000 | |
| FOS_HIDEMRUPLACES = 0x00020000 | |
| FOS_HIDEPINNEDPLACES = 0x00040000 | |
| FOS_NODEREFERENCELINKS = 0x00100000 | |
| FOS_DONTADDTORECENT = 0x02000000 | |
| FOS_FORCESHOWHIDDEN = 0x10000000 | |
| FOS_DEFAULTNOMINIMODE = 0x20000000 | |
| FOS_FORCEPREVIEWPANEON = 0x40000000 | |
| FOS_DEFAULTFOLDERS = 0x2028 | |
| FOS_FILESEARCH = 0x1008 | |
| ffi.cdef[[ | |
| typedef char* STRING; | |
| typedef const char* CSTRING; | |
| typedef wchar_t* WSTRING; | |
| typedef const WSTRING CWSTRING; | |
| typedef struct HWND__ { int unused; } *HWND; | |
| typedef struct _SHITEMID { unsigned short cb; unsigned char abID[ 1 ]; } SHITEMID; | |
| typedef struct _ITEMIDLIST { SHITEMID mkid; } ITEMIDLIST; | |
| typedef struct _GUID { | |
| unsigned long data1; | |
| unsigned short data2; | |
| unsigned short data3; | |
| unsigned char data4[8]; | |
| } GUID; | |
| typedef struct _COMDLG_FILTERSPEC { | |
| WSTRING pszName; | |
| WSTRING pszSpec; | |
| } COMDLG_FILTERSPEC; | |
| typedef struct tagBIND_OPTS { | |
| unsigned long cbStruct; | |
| unsigned long grfFlags; | |
| unsigned long grfMode; | |
| unsigned long dwTickCountDeadline; | |
| } BIND_OPTS; | |
| typedef struct _tagpropertykey { | |
| GUID fmtid; | |
| unsigned long pid; | |
| } PROPERTYKEY; | |
| typedef struct _FILETIME { | |
| unsigned long dwLowDateTime; | |
| unsigned long dwHighDateTime; | |
| } FILETIME, *PFILETIME, *LPFILETIME; | |
| typedef struct _WIN32_FIND_DATAA { | |
| unsigned long dwFileAttributes; | |
| FILETIME ftCreationTime; | |
| FILETIME ftLastAccessTime; | |
| FILETIME ftLastWriteTime; | |
| unsigned long nFileSizeHigh; | |
| unsigned long nFileSizeLow; | |
| unsigned long dwReserved0; | |
| unsigned long dwReserved1; | |
| char cFileName[260]; | |
| char cAlternateFileName[14]; | |
| } WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA; | |
| typedef enum _SIGDN { | |
| SIGDN_NORMALDISPLAY = 0, | |
| SIGDN_PARENTRELATIVEPARSING = (int) 0x80018001, | |
| SIGDN_DESKTOPABSOLUTEPARSING = (int) 0x80028000, | |
| SIGDN_PARENTRELATIVEEDITING = (int) 0x80031001, | |
| SIGDN_DESKTOPABSOLUTEEDITING = (int) 0x8004c000, | |
| SIGDN_FILESYSPATH = (int) 0x80058000, | |
| SIGDN_URL = (int) 0x80068000, | |
| SIGDN_PARENTRELATIVEFORADDRESSBAR = (int) 0x8007c001, | |
| SIGDN_PARENTRELATIVE = (int) 0x80080001 | |
| } SIGDN; | |
| typedef enum FDAP { | |
| FDAP_BOTTOM = 0, | |
| FDAP_TOP = 1 | |
| } FDAP; | |
| typedef enum GETPROPERTYSTOREFLAGS { | |
| GPS_DEFAULT = 0, | |
| GPS_HANDLERPROPERTIESONLY = 0x1, | |
| GPS_READWRITE = 0x2, | |
| GPS_TEMPORARY = 0x4, | |
| GPS_FASTPROPERTIESONLY = 0x8, | |
| GPS_OPENSLOWITEM = 0x10, | |
| GPS_DELAYCREATION = 0x20, | |
| GPS_BESTEFFORT = 0x40, | |
| GPS_NO_OPLOCK = 0x80, | |
| GPS_MASK_VALID = 0xff | |
| } GETPROPERTYSTOREFLAGS; | |
| typedef enum SIATTRIBFLAGS { | |
| SIATTRIBFLAGS_AND = 0x1, | |
| SIATTRIBFLAGS_OR = 0x2, | |
| SIATTRIBFLAGS_APPCOMPAT = 0x3, | |
| SIATTRIBFLAGS_MASK = 0x3, | |
| SIATTRIBFLAGS_ALLITEMS = 0x4000 | |
| } SIATTRIBFLAGS; | |
| typedef struct IUnknown IUnknown; | |
| typedef struct IBindCtx IBindCtx; | |
| typedef struct IShellItem IShellItem; | |
| typedef struct IFileDialogEvents IFileDialogEvents; | |
| typedef struct IFileDialog IFileDialog; | |
| typedef struct IFileSaveDialog IFileSaveDialog; | |
| typedef struct IFileOpenDialog IFileOpenDialog; | |
| typedef struct IShellItemFilter IShellItemFilter; | |
| typedef struct IShellItemArray IShellItemArray; | |
| typedef struct IEnumShellItems IEnumShellItems; | |
| typedef struct IShellLinkA IShellLinkA; | |
| typedef struct IShellLinkDataList IShellLinkDataList; | |
| typedef struct IResolveShellLink IResolveShellLink; | |
| typedef struct IPersistFile IPersistFile; | |
| struct IUnknownVtbl { | |
| long (*QueryInterface) (IUnknown * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IUnknown * This); | |
| unsigned long (*Release) (IUnknown * This); | |
| }; | |
| struct IUnknown { struct IUnknownVtbl *lpVtbl; }; | |
| struct IBindCtxVtbl { | |
| long (*QueryInterface) (IBindCtx * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IBindCtx * This); | |
| unsigned long (*Release) (IBindCtx * This); | |
| long (*RegisterObjectBound) (IBindCtx * This, IUnknown * punk); | |
| long (*RevokeObjectBound) (IBindCtx * This, IUnknown * punk); | |
| long (*ReleaseBoundObjects) (IBindCtx * This); | |
| long (*SetBindOptions) (IBindCtx * This, BIND_OPTS * pbindopts); | |
| long (*GetBindOptions) (IBindCtx * This, BIND_OPTS * pbindopts); | |
| long (*GetRunningObjectTable) (IBindCtx * This, void **pprot); | |
| long (*RegisterObjectParam) (IBindCtx * This, WSTRING pszKey, IUnknown * punk); | |
| long (*GetObjectParam) (IBindCtx * This, WSTRING pszKey, IUnknown **ppunk); | |
| long (*EnumObjectParam) (IBindCtx * This, void **ppenum); | |
| long (*RevokeObjectParam) (IBindCtx * This, WSTRING pszKey); | |
| }; | |
| struct IBindCtx { struct IBindCtxVtbl *lpVtbl; }; | |
| struct IShellItemVtbl { | |
| long (*QueryInterface) (IShellItem * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IShellItem * This); | |
| unsigned long (*Release) (IShellItem * This); | |
| long (*BindToHandler) | |
| ( | |
| IShellItem * This, | |
| IBindCtx * pbc, | |
| const GUID * const bhid, | |
| const GUID * const riid, | |
| void **ppv | |
| ); | |
| long (*GetParent) (IShellItem * This, IShellItem **ppsi); | |
| long (*GetDisplayName) (IShellItem * This, SIGDN sigdnName, WSTRING *ppszName); | |
| long (*GetAttributes) (IShellItem * This, unsigned long sfgaoMask, unsigned long *psfgaoAttribs); | |
| long (*Compare) (IShellItem * This, IShellItem * psi, unsigned long hint, int *piOrder); | |
| }; | |
| struct IShellItem { struct IShellItemVtbl *lpVtbl; }; | |
| struct IFileDialogEventsVtbl { | |
| long (*QueryInterface) (IFileDialogEvents * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IFileDialogEvents * This); | |
| unsigned long (*Release) (IFileDialogEvents * This); | |
| long (*OnFileOk) (IFileDialogEvents * This, IFileDialog * pfd); | |
| long (*OnFolderChanging) (IFileDialogEvents * This, IFileDialog * pfd, IShellItem * psiFolder); | |
| long (*OnFolderChange) (IFileDialogEvents * This, IFileDialog * pfd); | |
| long (*OnSelectionChange) (IFileDialogEvents * This, IFileDialog * pfd); | |
| long (*OnShareViolation) | |
| ( | |
| IFileDialogEvents * This, | |
| IFileDialog * pfd, | |
| IShellItem * psi, | |
| void * pResponse | |
| ); | |
| long (*OnTypeChange) (IFileDialogEvents * This, IFileDialog * pfd); | |
| long (*OnOverwrite) | |
| ( | |
| IFileDialogEvents * This, | |
| IFileDialog * pfd, | |
| IShellItem * psi, | |
| void * pResponse | |
| ); | |
| }; | |
| struct IFileDialogEvents { struct IFileDialogEventsVtbl *lpVtbl; }; | |
| struct IFileDialogVtbl { | |
| long (*QueryInterface) (IFileDialog * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IFileDialog * This); | |
| unsigned long (*Release) (IFileDialog * This); | |
| long (*Show) (IFileDialog * This, HWND hwndOwner); | |
| long (*SetFileTypes) (IFileDialog * This, unsigned int cFileTypes, const COMDLG_FILTERSPEC * rgFilterSpec); | |
| long (*SetFileTypeIndex) (IFileDialog * This, unsigned int iFileType); | |
| long (*GetFileTypeIndex) (IFileDialog * This, unsigned int *piFileType); | |
| long (*Advise) (IFileDialog * This, IFileDialogEvents * pfde, unsigned long *pdwCookie); | |
| long (*Unadvise) (IFileDialog * This, unsigned long dwCookie); | |
| long (*SetOptions) (IFileDialog * This, unsigned long fos); | |
| long (*GetOptions) (IFileDialog * This, unsigned long *pfos); | |
| long (*SetDefaultFolder) (IFileDialog * This, IShellItem * psi); | |
| long (*SetFolder) (IFileDialog * This, IShellItem * psi); | |
| long (*GetFolder) (IFileDialog * This, IShellItem **ppsi); | |
| long (*GetCurrentSelection) (IFileDialog * This, IShellItem **ppsi); | |
| long (*SetFileName) (IFileDialog * This, CWSTRING pszName); | |
| long (*GetFileName) (IFileDialog * This, WSTRING**pszName); | |
| long (*SetTitle) (IFileDialog * This, CWSTRING pszTitle); | |
| long (*SetOkButtonLabel) (IFileDialog * This, CWSTRING pszText); | |
| long (*SetFileNameLabel) (IFileDialog * This, CWSTRING pszLabel); | |
| long (*GetResult) (IFileDialog * This, IShellItem **ppsi); | |
| long (*AddPlace) (IFileDialog * This, IShellItem * psi, FDAP fdap); | |
| long (*SetDefaultExtension) (IFileDialog * This, CWSTRING pszDefaultExtension); | |
| long (*Close) (IFileDialog * This, long hr); | |
| long (*SetClientGuid) (IFileDialog * This, const GUID * const guid); | |
| long (*ClearClientData) (IFileDialog * This); | |
| long (*SetFilter) (IFileDialog * This, IShellItemFilter * pFilter); | |
| }; | |
| struct IFileDialog { struct IFileDialogVtbl *lpVtbl; }; | |
| struct IFileSaveDialogVtbl { | |
| long (*QueryInterface) (IFileSaveDialog * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IFileSaveDialog * This); | |
| unsigned long (*Release) (IFileSaveDialog * This); | |
| long (*Show) (IFileSaveDialog * This, HWND hwndOwner); | |
| long (*SetFileTypes) (IFileSaveDialog * This, unsigned int cFileTypes, const COMDLG_FILTERSPEC * rgFilterSpec); | |
| long (*SetFileTypeIndex) (IFileSaveDialog * This, unsigned int iFileType); | |
| long (*GetFileTypeIndex) (IFileSaveDialog * This, unsigned int *piFileType); | |
| long (*Advise) (IFileSaveDialog * This, IFileDialogEvents * pfde, unsigned long *pdwCookie); | |
| long (*Unadvise) (IFileSaveDialog * This, unsigned long dwCookie); | |
| long (*SetOptions) (IFileSaveDialog * This, unsigned long fos); | |
| long (*GetOptions) (IFileSaveDialog * This, unsigned long *pfos); | |
| long (*SetDefaultFolder) (IFileSaveDialog * This, IShellItem * psi); | |
| long (*SetFolder) (IFileSaveDialog * This, IShellItem * psi); | |
| long (*GetFolder) (IFileSaveDialog * This, IShellItem **ppsi); | |
| long (*GetCurrentSelection) (IFileSaveDialog * This, IShellItem **ppsi); | |
| long (*SetFileName) (IFileSaveDialog * This, CWSTRING pszName); | |
| long (*GetFileName) (IFileSaveDialog * This, WSTRING *pszName); | |
| long (*SetTitle) (IFileSaveDialog * This, CWSTRING pszTitle); | |
| long (*SetOkButtonLabel) (IFileSaveDialog * This, CWSTRING pszText); | |
| long (*SetFileNameLabel) (IFileSaveDialog * This, CWSTRING pszLabel); | |
| long (*GetResult) (IFileSaveDialog * This, IShellItem **ppsi); | |
| long (*AddPlace) (IFileSaveDialog * This, IShellItem * psi, FDAP fdap); | |
| long (*SetDefaultExtension) (IFileSaveDialog * This, CWSTRING pszDefaultExtension); | |
| long (*Close) (IFileSaveDialog * This, long hr); | |
| long (*SetClientGuid) (IFileSaveDialog * This, const GUID * const guid); | |
| long (*ClearClientData) (IFileSaveDialog * This); | |
| long (*SetFilter) (IFileSaveDialog * This, IShellItemFilter * pFilter); | |
| long (*SetSaveAsItem) (IFileSaveDialog * This, IShellItem * psi); | |
| long (*SetProperties) (IFileSaveDialog * This, void * pStore); | |
| long (*SetCollectedProperties) (IFileSaveDialog * This, void * pList, int fAppendDefault); | |
| long (*GetProperties) (IFileSaveDialog * This, void **ppStore); | |
| long (*ApplyProperties) | |
| ( | |
| IFileSaveDialog * This, | |
| IShellItem * psi, | |
| void * pStore, | |
| HWND hwnd, | |
| void * pSink | |
| ); | |
| }; | |
| struct IFileSaveDialog { struct IFileSaveDialogVtbl *lpVtbl; }; | |
| struct IFileOpenDialogVtbl { | |
| long (*QueryInterface) (IFileOpenDialog * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IFileOpenDialog * This); | |
| unsigned long (*Release) (IFileOpenDialog * This); | |
| long (*Show) (IFileOpenDialog * This, HWND hwndOwner); | |
| long (*SetFileTypes) (IFileOpenDialog * This, unsigned int cFileTypes, const COMDLG_FILTERSPEC * rgFilterSpec); | |
| long (*SetFileTypeIndex) (IFileOpenDialog * This, unsigned int iFileType); | |
| long (*GetFileTypeIndex) (IFileOpenDialog * This, unsigned int *piFileType); | |
| long (*Advise) (IFileOpenDialog * This, IFileDialogEvents * pfde, unsigned long *pdwCookie); | |
| long (*Unadvise) (IFileOpenDialog * This, unsigned long dwCookie); | |
| long (*SetOptions) (IFileOpenDialog * This, unsigned long fos); | |
| long (*GetOptions) (IFileOpenDialog * This, unsigned long *pfos); | |
| long (*SetDefaultFolder) (IFileOpenDialog * This, IShellItem * psi); | |
| long (*SetFolder) (IFileOpenDialog * This, IShellItem * psi); | |
| long (*GetFolder) (IFileOpenDialog * This, IShellItem **ppsi); | |
| long (*GetCurrentSelection) (IFileOpenDialog * This, IShellItem **ppsi); | |
| long (*SetFileName) (IFileOpenDialog * This, CWSTRING pszName); | |
| long (*GetFileName) (IFileOpenDialog * This, WSTRING *pszName); | |
| long (*SetTitle) (IFileOpenDialog * This, CWSTRING pszTitle); | |
| long (*SetOkButtonLabel) (IFileOpenDialog * This, CWSTRING pszText); | |
| long (*SetFileNameLabel) (IFileOpenDialog * This, CWSTRING pszLabel); | |
| long (*GetResult) (IFileOpenDialog * This, IShellItem **ppsi); | |
| long (*AddPlace) (IFileOpenDialog * This, IShellItem * psi, FDAP fdap); | |
| long (*SetDefaultExtension) (IFileOpenDialog * This, CWSTRING pszDefaultExtension); | |
| long (*Close) (IFileOpenDialog * This, long hr); | |
| long (*SetClientGuid) (IFileOpenDialog * This, const GUID * const guid); | |
| long (*ClearClientData) (IFileOpenDialog * This); | |
| long (*SetFilter) (IFileOpenDialog * This, IShellItemFilter * pFilter); | |
| long (*GetResults) (IFileOpenDialog * This, IShellItemArray **ppenum); | |
| long (*GetSelectedItems) (IFileOpenDialog * This, IShellItemArray **ppsai); | |
| }; | |
| struct IFileOpenDialog { struct IFileOpenDialogVtbl *lpVtbl; }; | |
| struct IShellItemFilterVtbl { | |
| long (*QueryInterface) (IShellItemFilter * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IShellItemFilter * This); | |
| unsigned long (*Release) (IShellItemFilter * This); | |
| long (*IncludeItem) (IShellItemFilter * This, IShellItem * psi); | |
| long (*GetEnumFlagsForItem) (IShellItemFilter * This, IShellItem * psi, unsigned long *pgrfFlags); | |
| }; | |
| struct IShellItemFilter { struct IShellItemFilterVtbl *lpVtbl; }; | |
| struct IShellItemArrayVtbl { | |
| long (*QueryInterface) (IShellItemArray * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IShellItemArray * This); | |
| unsigned long (*Release) (IShellItemArray * This); | |
| long (*BindToHandler) | |
| ( | |
| IShellItemArray * This, | |
| IBindCtx * pbc, | |
| const GUID * const bhid, | |
| const GUID * const riid, | |
| void **ppvOut | |
| ); | |
| long (*GetPropertyStore) (IShellItemArray * This, GETPROPERTYSTOREFLAGS flags, const GUID * const riid, void **ppv); | |
| long (*GetPropertyDescriptionList) | |
| ( | |
| IShellItemArray * This, | |
| const PROPERTYKEY * const keyType, | |
| const GUID * const riid, | |
| void **ppv | |
| ); | |
| long (*GetAttributes) | |
| ( | |
| IShellItemArray * This, | |
| SIATTRIBFLAGS AttribFlags, | |
| unsigned long sfgaoMask, | |
| unsigned long *psfgaoAttribs | |
| ); | |
| long (*GetCount) (IShellItemArray * This, unsigned long *pdwNumItems); | |
| long (*GetItemAt) (IShellItemArray * This, unsigned long dwIndex, IShellItem **ppsi); | |
| long (*EnumItems) (IShellItemArray * This, IEnumShellItems **ppenumShellItems); | |
| }; | |
| struct IShellItemArray { struct IShellItemArrayVtbl *lpVtbl; }; | |
| struct IEnumShellItemsVtbl { | |
| long (*QueryInterface) (IEnumShellItems * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IEnumShellItems * This); | |
| unsigned long (*Release) (IEnumShellItems * This); | |
| long (*Next) (IEnumShellItems * This, unsigned long celt, IShellItem **rgelt, unsigned long *pceltFetched); | |
| long (*Skip) (IEnumShellItems * This, unsigned long celt); | |
| long (*Reset) (IEnumShellItems * This); | |
| long (*Clone) (IEnumShellItems * This, IEnumShellItems **ppenum); | |
| }; | |
| struct IEnumShellItems { struct IEnumShellItemsVtbl *lpVtbl; }; | |
| typedef IShellItem* LP_IShellItem; | |
| struct IShellLinkAVtbl { | |
| long (*QueryInterface) (IShellLinkA * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IShellLinkA * This); | |
| unsigned long (*Release) (IShellLinkA * This); | |
| long (*GetPath) (IShellLinkA * This, char **pszFile, int cch, WIN32_FIND_DATAA * pfd, unsigned long fFlags); | |
| long (*GetIDList) (IShellLinkA * This, ITEMIDLIST **ppidl); | |
| long (*SetIDList) (IShellLinkA * This, const ITEMIDLIST * pidl); | |
| long (*GetDescription) (IShellLinkA * This, char **pszName, int cch); | |
| long (*SetDescription) (IShellLinkA * This, const char *pszName); | |
| long (*GetWorkingDirectory) (IShellLinkA * This, char **pszDir, int cch); | |
| long (*SetWorkingDirectory) (IShellLinkA * This, const char *pszDir); | |
| long (*GetArguments) (IShellLinkA * This, char **pszArgs, int cch); | |
| long (*SetArguments) (IShellLinkA * This, const char *pszArgs); | |
| long (*GetHotkey) (IShellLinkA * This, unsigned short *pwHotkey); | |
| long (*SetHotkey) (IShellLinkA * This, unsigned short wHotkey); | |
| long (*GetShowCmd) (IShellLinkA * This, int *piShowCmd); | |
| long (*SetShowCmd) (IShellLinkA * This, int iShowCmd); | |
| long (*GetIconLocation) (IShellLinkA * This, char **pszIconPath, int cch, int *piIcon); | |
| long (*SetIconLocation) (IShellLinkA * This, const char *pszIconPath, int iIcon); | |
| long (*SetRelativePath) (IShellLinkA * This, const char *pszPathRel, unsigned long dwReserved); | |
| long (*Resolve) (IShellLinkA * This, HWND hwnd, unsigned long fFlags); | |
| long (*SetPath) (IShellLinkA * This, const char *pszFile); | |
| }; | |
| struct IShellLinkA { struct IShellLinkAVtbl *lpVtbl; }; | |
| struct IPersistFileVtbl { | |
| long (*QueryInterface) (IPersistFile * This, const GUID * const riid, void **ppvObject); | |
| unsigned long (*AddRef) (IPersistFile * This); | |
| unsigned long (*Release) (IPersistFile * This); | |
| long (*GetClassID) (IPersistFile * This, GUID * pClassID); | |
| long (*IsDirty) (IPersistFile * This); | |
| long (*Load) (IPersistFile * This, const unsigned short *pszFileName, unsigned long dwMode); | |
| long (*Save) (IPersistFile * This, const unsigned short *pszFileName, int fRemember); | |
| long (*SaveCompleted) (IPersistFile * This, const unsigned short *pszFileName); | |
| long (*GetCurFile) (IPersistFile * This, unsigned short **ppszFileName); | |
| }; | |
| struct IPersistFile { struct IPersistFileVtbl *lpVtbl; }; | |
| long CoInitialize(void* pvReserved); | |
| void CoUninitialize(void); | |
| long CoCreateInstance(const GUID* const rclsid, IUnknown* pUnkOuter, unsigned long dwClsContext, const GUID* const riid, void** ppv); | |
| long CoGetObjectContext(const GUID * const riid, void* * ppv); | |
| long CoGetClassObject(const GUID * const rclsid, unsigned long dwClsContext, void* pvReserved, const GUID * const riid, void* * ppv); | |
| long CoRegisterClassObject(const GUID * const rclsid, IUnknown* pUnk, unsigned long dwClsContext, unsigned long flags, unsigned long* lpdwRegister); | |
| long CoRevokeClassObject(unsigned long dwRegister); | |
| long CoResumeClassObjects(void); | |
| long CoSuspendClassObjects(void); | |
| unsigned long CoAddRefServerProcess(void); | |
| unsigned long CoReleaseServerProcess(void); | |
| long SHCreateItemFromParsingName(CWSTRING pszPath, IBindCtx *pbc, const GUID * const riid, void **ppv); | |
| long RpcStringFreeW(WSTRING s); | |
| unsigned int wcslen(CWSTRING s); | |
| unsigned int strlen(CSTRING s); | |
| unsigned int wcstombs(STRING s, CWSTRING w, unsigned int c); | |
| unsigned int mbstowcs(WSTRING w, CSTRING s, unsigned int c); | |
| char *strcpy(char* d, const char* s); | |
| ]] | |
| -- pStore IPropertyStore | |
| -- pList IPropertyDescriptionList | |
| -- pSink IFileOperationProgressSink | |
| function GUID(bytes) | |
| local guid = ffi.new('GUID[1]') | |
| if type(bytes) == 'table' then | |
| local c = 4 | |
| guid[0].data1 = bytes[1] | |
| guid[0].data2 = bytes[2] | |
| guid[0].data3 = bytes[3] | |
| for i = 0,7 do | |
| guid[0].data4[i] = bytes[c+i] | |
| end | |
| else | |
| print('Dont know what to do with non-table guid value.') | |
| end | |
| return guid | |
| end | |
| CLSID_FileOpenDialog = GUID({ 0xDC1C5A9C, 0xE88A, 0x4DDE, 0xA5, 0xA1, 0x60, 0xF8, 0x2A, 0x20, 0xAE, 0xF7 }) | |
| CLSID_FileSaveDialog = GUID({ 0xC0B4E2F3, 0xBA21, 0x4773, 0x8D, 0xBA, 0x33, 0x5E, 0xC9, 0x46, 0xEB, 0x8B }) | |
| CLSID_ShellLink = GUID({ 0x00021401, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }) | |
| IID_IFileDialog = GUID({ 0x42F85136, 0xDB7E, 0x439C, 0x85, 0xF1, 0xE4, 0x07, 0x5D, 0x13, 0x5F, 0xC8 }) | |
| IID_IFileSaveDialog = GUID({ 0x84BCCD23, 0x5FDE, 0x4CDB, 0xAE, 0xA4, 0xAF, 0x64, 0xB8, 0x3D, 0x78, 0xAB }) | |
| IID_IFileOpenDialog = GUID({ 0xD57C7288, 0xD4AD, 0x4768, 0xBE, 0x02, 0x9D, 0x96, 0x95, 0x32, 0xD9, 0x60 }) | |
| IID_IFileDialogCustomize = GUID({ 0xE6FDD21A, 0x163F, 0x4975, 0x9C, 0x8C, 0xA6, 0x9F, 0x1B, 0xA3, 0x70, 0x34 }) | |
| IID_IFileDialogEvents = GUID({ 0x973510DB, 0x7D7F, 0x452B, 0x89, 0x75, 0x74, 0xA8, 0x58, 0x28, 0xD3, 0x54 }) | |
| IID_IShellItem = GUID({ 0x43826D1E, 0xE718, 0x42EE, 0xBC, 0x55, 0xA1, 0xE2, 0x61, 0xC3, 0x7B, 0xFE }) | |
| IID_IShellLinkA = GUID({ 0x000214EE, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }) | |
| IID_IPersistFile = GUID({ 0x0000010B, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }) | |
| function wstr2str(ws) | |
| local szbuf = ffi.C.wcslen(ws) | |
| local buf = ffi.new('char[?]', szbuf+1) | |
| if ffi.C.wcstombs(buf, ws, szbuf) == -1 then | |
| return nil | |
| end | |
| return ffi.string(buf, szbuf) | |
| end | |
| function str2wstr(s) | |
| local szbuf = s:len() | |
| local buf = ffi.new('wchar_t[?]', szbuf+1) | |
| if ffi.C.mbstowcs(buf, s, szbuf) == -1 then | |
| return nil | |
| end | |
| return buf | |
| end | |
| function str2cstr(s) | |
| local szbuf = s:len() | |
| local buf = ffi.new('char[?]', szbuf+1) | |
| ffi.C.strcpy(buf, s) | |
| return buf | |
| end | |
| function shellitem2path(si) | |
| local sdisplay = ffi.new('WSTRING[1]') | |
| if si.lpVtbl.GetDisplayName(si, ffi.C.SIGDN_DESKTOPABSOLUTEPARSING, sdisplay) < 0 then | |
| print('IShellItem.GetDisplayName failed') | |
| si.lpVtbl.Release(si) | |
| return nil | |
| end | |
| local result = wstr2str(sdisplay[0]) | |
| if result == nil then | |
| print('Failed to convert resulting wstring to a string.') | |
| result = nil | |
| end | |
| return result | |
| end | |
| function path2shellitem(fpath) | |
| local psi = ffi.new('IShellItem*[1]') | |
| local ppath = str2wstr(fpath) | |
| if shell32.SHCreateItemFromParsingName(ppath, nil, IID_IShellItem, ffi.cast('void**', psi)) < 0 then | |
| return nil | |
| end | |
| local result = psi[0] | |
| return result | |
| end | |
| -- TODO: Declare the following in our metatable | |
| -- long (*GetFolder) (IFileDialog * This, IShellItem **ppsi); | |
| -- long (*GetCurrentSelection) (IFileDialog * This, IShellItem **ppsi); | |
| -- long (*SetFileName) (IFileDialog * This, CWSTRING pszName); | |
| -- long (*GetFileName) (IFileDialog * This, WSTRING**pszName); | |
| -- long (*SetFileNameLabel) (IFileDialog * This, CWSTRING pszLabel); | |
| -- long (*AddPlace) (IFileDialog * This, IShellItem * psi, FDAP fdap); | |
| -- long (*SetDefaultExtension) (IFileDialog * This, CWSTRING pszDefaultExtension); | |
| -- long (*Close) (IFileDialog * This, long hr); | |
| -- long (*SetClientGuid) (IFileDialog * This, const GUID * const guid); | |
| -- long (*ClearClientData) (IFileDialog * This); | |
| -- long (*SetFilter) (IFileDialog * This, IShellItemFilter * pFilter); | |
| IFileDialog_mt = { | |
| __index = { | |
| QueryInterface = function(self, riid, ppobj) | |
| if type(riid) == 'table' then | |
| riid = GUID(riid) | |
| end | |
| return (self.lpVtbl.QueryInterface(self, riid, ffi.cast('void**', ppobj)) >= 0) | |
| end, | |
| -- Returns true or false depending | |
| Show = function(self, hwnd) | |
| return (self.lpVtbl.Show(self, ffi.cast('HWND', hwnd)) >= 0) | |
| end, | |
| -- Expects a table of filters where keys represent filter names, and values represet patterns. | |
| SetFileTypes = function(self, filters) | |
| local count = table.getn(filters) | |
| local filtspecs = ffi.new('COMDLG_FILTERSPEC[?]', count) | |
| local i = 0 | |
| for idx,spec in ipairs(filters) do | |
| filtspecs[i].pszName = str2wstr(spec[1]) | |
| filtspecs[i].pszSpec = str2wstr(spec[2]) | |
| i = i + 1 | |
| end | |
| return (self.lpVtbl.SetFileTypes(self, count, filtspecs) >= 0) | |
| end, | |
| SetFileTypeIndex = function(self, index) | |
| return (self.lpVtbl.SetFileTypeIndex(self, index) >= 0) | |
| end, | |
| -- Returns -1 on failure. | |
| GetFileTypeIndex = function(self) | |
| local pbuf = ffi.new('unsigned int[1]') | |
| if self.lpVtbl.GetFileTypeIndex(self, buf) >= 0 then | |
| return tonumber(buf[0]) | |
| else | |
| return -1 | |
| end | |
| end, | |
| -- Need to figure out how to do bitmasks in lua. | |
| SetOptions = function(self, dwOptions) | |
| return (self.lpVtbl.SetOptions(self, dwOptions) >= 0) | |
| end, | |
| -- Returns nil on failure. | |
| GetOptions = function(self) | |
| local pbuf = ffi.new('unsigned long[1]') | |
| if self.lpVtbl.GetOptions(self, pbuf) >= 0 then | |
| return pbuf[0] | |
| else | |
| return nil | |
| end | |
| end, | |
| SetDefaultFolder = function(self, folder) | |
| return (self.lpVtbl.SetDefaultFolder(self, path2shellitem(folder)) >= 0) | |
| end, | |
| SetFolder = function(self, folder) | |
| return (self.lpVtbl.SetFolder(self, path2shellitem(folder)) >= 0) | |
| end, | |
| SetOkButtonLabel = function(self, lbl) | |
| return (self.lpVtbl.SetOkButtonLabel(self, str2wstr(lbl)) >= 0) | |
| end, | |
| SetTitle = function(self, title) | |
| return (self.lpVtbl.SetTitle(self, str2wstr(title)) >= 0) | |
| end, | |
| -- Returns nil on failure. | |
| GetResult = function(self, psi) | |
| local psi = ffi.new('IShellItem*[1]') | |
| if self.lpVtbl.GetResult(self, psi) >= 0 then | |
| return psi[0] | |
| else | |
| return nil | |
| end | |
| end, | |
| Release = function(self) | |
| self.lpVtbl.Release(self) | |
| end, | |
| }, | |
| } | |
| IFileDialog = ffi.metatype('IFileDialog', IFileDialog_mt) | |
| function select_folder(default_folder) | |
| local result = nil | |
| if ole32.CoInitialize(nil) > 0 then | |
| print('ole32.CoInitialize failed') | |
| return nil | |
| end | |
| local pdialog = ffi.new('IFileDialog*[1]') | |
| if ole32.CoCreateInstance(CLSID_FileOpenDialog, nil, CLSCTX_INPROC_SERVER, IID_IFileDialog, ffi.cast('void**', pdialog)) < 0 then | |
| print('ole32.CoCreateInstance failed') | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| local dialog = pdialog[0] | |
| dialog:SetOptions(FOS_DEFAULTFOLDERS) | |
| dialog:SetTitle('Select a folder..') | |
| dialog:SetOkButtonLabel('Select') | |
| if default_folder ~= nil then | |
| dialog:SetFolder(default_folder) | |
| end | |
| if not dialog:Show(nil) then | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| local si = dialog:GetResult() | |
| if si == nil then | |
| print('IFileDialog->GetResult failed') | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| result = shellitem2path(si) | |
| si.lpVtbl.Release(si) | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return result | |
| end | |
| function open_file(kwargs) | |
| setmetatable(kwargs,{ | |
| __index={ | |
| title='Open file..', | |
| ok='Open', | |
| folder=nil, | |
| filters={ | |
| {'All filetypes', '*.*'} | |
| } | |
| } | |
| }) | |
| local title, ok, folder, filters = | |
| kwargs[1] or kwargs.title, | |
| kwargs[2] or kwargs.ok, | |
| kwargs[3] or kwargs.folder, | |
| kwargs[4] or kwargs.filters | |
| local result = nil | |
| if ole32.CoInitialize(nil) > 0 then | |
| print('ole32.CoInitialize failed') | |
| return nil | |
| end | |
| local pdialog = ffi.new('IFileDialog*[1]') | |
| if ole32.CoCreateInstance(CLSID_FileOpenDialog, nil, CLSCTX_INPROC_SERVER, IID_IFileDialog, ffi.cast('void**', pdialog)) < 0 then | |
| print('ole32.CoCreateInstance failed') | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| local dialog = pdialog[0] | |
| dialog:SetOptions(FOS_FILESEARCH) | |
| dialog:SetTitle(title) | |
| dialog:SetOkButtonLabel(ok) | |
| dialog:SetFileTypes(filters) | |
| if folder ~= nil then | |
| dialog:SetFolder(folder) | |
| end | |
| if not dialog:Show(nil) then | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| local si = dialog:GetResult() | |
| if si == nil then | |
| print('IFileDialog->GetResult failed') | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| result = shellitem2path(si) | |
| si.lpVtbl.Release(si) | |
| dialog:Release() | |
| ole32.CoUninitialize() | |
| return result | |
| end | |
| -- This should probably be overhauled and made.. good. | |
| function shortcut(linkpath, filepath, kwargs) | |
| setmetatable(kwargs,{ | |
| __index={ | |
| icon=nil, | |
| cwd=nil, | |
| desc=nil | |
| } | |
| }) | |
| local icon, cwd, args, desc, result = | |
| kwargs[1] or kwargs.icon, | |
| kwargs[2] or kwargs.cwd, | |
| kwargs[3] or kwargs.args, | |
| kwargs[4] or kwargs.desc, | |
| nil | |
| if ole32.CoInitialize(nil) > 0 then | |
| print('ole32.CoInitialize failed') | |
| return nil | |
| end | |
| local plink = ffi.new('IShellLinkA*[1]') | |
| if ole32.CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IID_IShellLinkA, ffi.cast('void**', plink)) < 0 then | |
| print('ole32.CoCreateInstance failed') | |
| ole32.CoUninitialize() | |
| return nil | |
| end | |
| local link = plink[0] | |
| link.lpVtbl.SetPath(link, filepath) | |
| if desc ~= nil then | |
| link.lpVtbl.SetDescription(link, desc) | |
| end | |
| if icon ~= nil then | |
| link.lpVtbl.SetIconLocation(link, icon, 0) | |
| end | |
| if cwd ~= nil then | |
| link.lpVtbl.SetWorkingDirectory(link, cwd) | |
| end | |
| if args ~= nil then | |
| link.lpVtbl.SetArguments(link, args) | |
| end | |
| local pperfile = ffi.new('IPersistFile*[1]') | |
| if link.lpVtbl.QueryInterface(link, IID_IPersistFile, ffi.cast('void**', pperfile)) < 0 then | |
| print('IShellLink.QueryInterface failed') | |
| else | |
| perfile = pperfile[0] | |
| perfile.lpVtbl.Save(perfile, str2wstr(linkpath), 1) | |
| perfile.lpVtbl.Release(perfile) | |
| result = true | |
| end | |
| link.lpVtbl.Release(link) | |
| ole32.CoUninitialize() | |
| return result | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment