mirror of https://github.com/bsnes-emu/bsnes.git
176 lines
5.1 KiB
C++
176 lines
5.1 KiB
C++
CShellExt::CShellExt() {
|
|
instanceCount = 0;
|
|
referenceCount++;
|
|
}
|
|
|
|
CShellExt::~CShellExt() {
|
|
referenceCount--;
|
|
}
|
|
|
|
STDMETHODIMP CShellExt::QueryInterface(REFIID riid, LPVOID *ppv) {
|
|
*ppv = nullptr;
|
|
|
|
if(IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) {
|
|
*ppv = (IShellExtInit*)this;
|
|
} else if(IsEqualIID(riid, IID_IContextMenu)) {
|
|
*ppv = (IContextMenu*)this;
|
|
}
|
|
|
|
if(*ppv) {
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShellExt::AddRef() {
|
|
return ++instanceCount;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShellExt::Release() {
|
|
if(--instanceCount) return instanceCount;
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, IDataObject *pDataObject, HKEY hRegKey) {
|
|
fileList.reset();
|
|
|
|
if(pDataObject) {
|
|
wchar_t filename[PATH_MAX];
|
|
STGMEDIUM medium;
|
|
FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
|
|
HDROP hDrop;
|
|
|
|
if(FAILED(pDataObject->GetData(&fe, &medium))) return E_INVALIDARG;
|
|
hDrop = (HDROP)GlobalLock(medium.hGlobal);
|
|
if(hDrop == NULL) return E_INVALIDARG;
|
|
|
|
fileList.reset();
|
|
unsigned count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0);
|
|
for(unsigned i = 0; i < count; i++) {
|
|
DragQueryFileW((HDROP)medium.hGlobal, i, filename, PATH_MAX);
|
|
string name = (const char*)utf8_t(filename);
|
|
name.transform("/", "\\");
|
|
if(name.endswith("\\")) name.rtrim<1>("\\");
|
|
fileList.append(name);
|
|
}
|
|
GlobalUnlock(medium.hGlobal);
|
|
ReleaseStgMedium(&medium);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CShellExt::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) {
|
|
settings.load();
|
|
unsigned idCmd = idCmdFirst;
|
|
bool firstDefault = true;
|
|
|
|
auto ruleIDs = matchedRules();
|
|
for(auto &ruleID : ruleIDs) {
|
|
auto &rule = settings.rules(ruleID);
|
|
if(idCmd < idCmdLast) {
|
|
InsertMenuW(hMenu, indexMenu, MF_STRING | MF_BYPOSITION, idCmd++, (const wchar_t*)utf16_t(rule.name));
|
|
if(rule.defaultAction && firstDefault) {
|
|
firstDefault = false; //there can be only one default menu item
|
|
SetMenuDefaultItem(hMenu, indexMenu, TRUE);
|
|
}
|
|
indexMenu++;
|
|
}
|
|
}
|
|
|
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(idCmd - idCmdFirst));
|
|
}
|
|
|
|
STDMETHODIMP CShellExt::GetCommandString(UINT_PTR idCmd, UINT uFlags, LPUINT lpReserved, LPSTR pszName, UINT uMaxNameLen) {
|
|
if(idCmd < settings.rules.size()) return S_OK;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
STDMETHODIMP CShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) {
|
|
if(HIWORD(lpcmi->lpVerb) != 0) return E_INVALIDARG; //ignore actual string verbs
|
|
|
|
settings.load();
|
|
unsigned id = LOWORD(lpcmi->lpVerb);
|
|
auto ruleIDs = matchedRules();
|
|
auto &rule = settings.rules(ruleIDs(id));
|
|
|
|
string nameID = fileList(0);
|
|
string pathnameID = dir(nameID).rtrim<1>("\\");
|
|
string filenameID = notdir(nameID);
|
|
string basenameID = notdir(nall::basename(nameID));
|
|
string extensionID = extension(nameID);
|
|
|
|
string pathID = {"\"", pathnameID, "\""};
|
|
string fileID = {"\"", nameID, "\""};
|
|
|
|
string pathsID, filesID;
|
|
for(auto &filename : fileList) pathsID.append("\"", dir(filename).rtrim<1>("\\"), "\"", " ");
|
|
for(auto &filename : fileList) filesID.append("\"", filename, "\"", " ");
|
|
pathsID.rtrim<1>(" "), filesID.rtrim<1>(" ");
|
|
|
|
lstring params = rule.command.qsplit<1>(" ");
|
|
params(1).replace("{name}", nameID);
|
|
params(1).replace("{pathname}", pathnameID);
|
|
params(1).replace("{filename}", filenameID);
|
|
params(1).replace("{basename}", basenameID);
|
|
params(1).replace("{extension}", extensionID);
|
|
|
|
params(1).replace("{path}", pathID);
|
|
params(1).replace("{file}", fileID);
|
|
|
|
params(1).replace("{paths}", pathsID);
|
|
params(1).replace("{files}", filesID);
|
|
|
|
if((intptr_t)ShellExecuteW(NULL, L"open", utf16_t(params(0)), utf16_t(params(1)), utf16_t(pathnameID), SW_SHOWNORMAL) <= 32) {
|
|
MessageBoxW(0, L"Error opening associated program.", L"kaijuu", MB_OK);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
vector<unsigned> CShellExt::matchedRules() {
|
|
vector<unsigned> matched;
|
|
if(fileList.size() == 0) return matched;
|
|
|
|
for(unsigned id = 0; id < settings.rules.size(); id++) {
|
|
auto &rule = settings.rules(id);
|
|
if(rule.multiSelection == false && fileList.size() > 1) continue;
|
|
bool proceed = true;
|
|
for(auto &filename : fileList) {
|
|
string name = filename;
|
|
if(directory::exists(name)) {
|
|
if(rule.matchFolders == false) {
|
|
proceed = false;
|
|
break;
|
|
}
|
|
} else {
|
|
if(rule.matchFiles == false) {
|
|
proceed = false;
|
|
break;
|
|
}
|
|
}
|
|
name = notdir(name);
|
|
|
|
lstring patternList = rule.pattern.split(";");
|
|
bool found = false;
|
|
for(auto &pattern : patternList) {
|
|
if(name.wildcard(pattern)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if(found == false) {
|
|
proceed = false;
|
|
break;
|
|
}
|
|
}
|
|
if(proceed == false) continue;
|
|
matched.append(id);
|
|
}
|
|
|
|
return matched;
|
|
}
|