bsnes/kaijuu/extension.cpp

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;
}