Skip to content

Instantly share code, notes, and snippets.

@juntalis
Last active December 18, 2015 12:59
Show Gist options
  • Select an option

  • Save juntalis/5786687 to your computer and use it in GitHub Desktop.

Select an option

Save juntalis/5786687 to your computer and use it in GitHub Desktop.
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