Skip to content
This repository was archived by the owner on Sep 2, 2021. It is now read-only.

Commit 8acda51

Browse files
authored
Merge pull request #677 from niteskum/graphicsFileExternalApplication
Shell Api to get default Application for a file type. API is added to get Default Application for a file type. Api Name: getSystemDefaultApp This takes input as comma separated file extensions string and return comma separated OS Default Application for each extensions if any.
2 parents 80b98d1 + 8b43b52 commit 8acda51

6 files changed

+269
-0
lines changed

appshell/appshell_extensions.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,23 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate {
432432
responseArgs->SetInt(2, port);
433433
}
434434

435+
} else if (message_name == "getSystemDefaultApp") {
436+
// Parameters:
437+
// 0: int32 - callback id
438+
// 1: string - list of file extensions
439+
if (argList->GetSize() != 2 ||
440+
argList->GetType(1) != VTYPE_STRING) {
441+
error = ERR_INVALID_PARAMS;
442+
}
443+
444+
ExtensionString defaultApp;
445+
if (error == NO_ERROR) {
446+
error = getSystemDefaultApp(argList->GetString(1), defaultApp);
447+
}
448+
449+
// Set response args for this function
450+
responseArgs->SetString(2, defaultApp);
451+
435452
} else if (message_name == "QuitApplication") {
436453
// Parameters - none
437454

appshell/appshell_extensions.js

+20
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,26 @@ if (!brackets) {
375375
}, path);
376376
};
377377

378+
/**
379+
* Checks If fileytype has assigned system default app
380+
*
381+
* @param {string} filetypes list of file Types for which deafult app to checked.
382+
* @param {function(err)} callback Asynchronous callback function. The callback gets two arguments
383+
* (filetypes, err)
384+
* filetypes which has system default app assigned.
385+
*
386+
* Possible error values:
387+
* NO_ERROR
388+
* ERR_INVALID_PARAMS
389+
* ERR_NOT_FOUND
390+
*
391+
* @return None. This is an asynchronous call that sends all return information to the callback.
392+
*/
393+
native function getSystemDefaultApp();
394+
appshell.app.getSystemDefaultApp = function (filetypes, callback) {
395+
getSystemDefaultApp(callback || _dummyCallback, filetypes);
396+
};
397+
378398
/**
379399
* Quits native shell application
380400
*/

appshell/appshell_extensions_gtk.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,11 @@ int32 OpenURLInDefaultBrowser(ExtensionString url)
210210
return NO_ERROR;
211211
}
212212

213+
int32 getSystemDefaultApp(const ExtensionString& fileTypes, ExtensionString& fileTypesWithdefaultApp)
214+
{
215+
return NO_ERROR;
216+
}
217+
213218
int32 IsNetworkDrive(ExtensionString path, bool& isRemote)
214219
{
215220
return NO_ERROR;

appshell/appshell_extensions_mac.mm

+56
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,62 @@ void CloseLiveBrowser(CefRefPtr<CefBrowser> browser, CefRefPtr<CefProcessMessage
391391
);
392392
}
393393

394+
int32 getSystemDefaultApp(const ExtensionString& fileTypes, ExtensionString& fileTypesWithdefaultApp)
395+
{
396+
397+
char delim[] = ",";
398+
char separator[] = "##";
399+
std::vector<ExtensionString> extArray;
400+
char* token = std::strtok((char*)fileTypes.c_str(), delim);
401+
while (token) {
402+
extArray.push_back(token);
403+
token = std::strtok(NULL, delim);
404+
}
405+
406+
for (std::vector<ExtensionString>::const_iterator it = extArray.begin(); it != extArray.end(); ++it)
407+
{
408+
ExtensionString appPath;
409+
410+
CFStringRef contentType = CFStringCreateWithCString (NULL, (*it).c_str(), kCFStringEncodingUTF8);
411+
412+
if(!contentType)
413+
continue;
414+
415+
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
416+
contentType,
417+
NULL);
418+
if(UTI)
419+
{
420+
CFURLRef bundle_id;
421+
422+
bundle_id = LSCopyDefaultApplicationURLForContentType(UTI, kLSRolesEditor, NULL);
423+
424+
if(bundle_id)
425+
{
426+
NSBundle *bundle = [NSBundle bundleWithURL: (NSURL*)bundle_id];
427+
428+
if (bundle)
429+
{
430+
appPath = [(NSString *)[bundle objectForInfoDictionaryKey: @"CFBundleExecutable"] cStringUsingEncoding:NSUTF8StringEncoding];
431+
}
432+
433+
fileTypesWithdefaultApp = fileTypesWithdefaultApp + *it + separator + appPath + ",";
434+
435+
CFRelease(bundle_id);
436+
}
437+
438+
CFRelease(UTI);
439+
}
440+
441+
CFRelease(contentType);
442+
}
443+
444+
return NO_ERROR;
445+
}
446+
447+
448+
449+
394450
int32 OpenURLInDefaultBrowser(ExtensionString url)
395451
{
396452
NSString* urlString = [NSString stringWithUTF8String:url.c_str()];

appshell/appshell_extensions_platform.h

+2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ void MoveFileOrDirectoryToTrash(ExtensionString filename, CefRefPtr<CefBrowser>
192192

193193
int32 CopyFile(ExtensionString src, ExtensionString dest);
194194

195+
int32 getSystemDefaultApp(const ExtensionString& fileTypes, ExtensionString& fileTypesWithdefaultApp);
196+
195197
int32 GetNodeState(int32& state);
196198

197199
void OnBeforeShutdown();

appshell/appshell_extensions_win.cpp

+169
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,175 @@ void CloseLiveBrowser(CefRefPtr<CefBrowser> browser, CefRefPtr<CefProcessMessage
403403
}
404404
}
405405

406+
407+
static BOOL ResolveAppPathCommon(const ExtensionString& lpszKey, const ExtensionString& lpszVal, ExtensionString& appPath)
408+
{
409+
HKEY keyRoot = NULL;
410+
BOOL result = FALSE;
411+
ULONG regKey(REG_SZ);
412+
413+
if (::RegOpenKeyEx(HKEY_CLASSES_ROOT, lpszKey.c_str(), 0, KEY_QUERY_VALUE, &keyRoot) == ERROR_SUCCESS)
414+
{
415+
TCHAR editorPath[255];
416+
ULONG fTypeSize = 255;
417+
418+
if (::RegQueryValueEx(keyRoot, lpszVal.c_str(), NULL, &regKey, (LPBYTE)editorPath, &fTypeSize) == ERROR_SUCCESS)
419+
{
420+
if (editorPath != L"")
421+
{
422+
appPath = editorPath;
423+
//appPath = appPath.substr(appPath.find_last_of(L"/\\") + 1);
424+
int iExe = appPath.find(L".exe");
425+
if (iExe == -1)
426+
iExe = appPath.find(L".EXE");
427+
if (iExe != -1)
428+
appPath = appPath.substr(0, iExe+4);
429+
430+
if (appPath[0] == '\"')
431+
appPath = appPath.substr(1);
432+
433+
result = TRUE;
434+
}
435+
436+
437+
}
438+
::RegCloseKey(keyRoot);
439+
}
440+
441+
return result;
442+
443+
}
444+
445+
static BOOL ResolveAppPathFromProgID(const ExtensionString& lpszProgID, ExtensionString& appPath)
446+
{
447+
448+
ExtensionString key = lpszProgID + L"\\shell\\open\\command";
449+
450+
451+
if (!ResolveAppPathCommon(key, L"", appPath))
452+
{
453+
key = lpszProgID + L"\\Application";
454+
if (ResolveAppPathCommon(key, L"AppUserModelID", appPath)) {
455+
appPath = appPath.substr(0, appPath.find(L"_"));
456+
return true;
457+
}
458+
return false;
459+
}
460+
return true;
461+
462+
}
463+
464+
BOOL GetShellDefaultOpenWithProgPath(const ExtensionString& fileExt, ExtensionString &appPath)
465+
{
466+
HKEY extKey = NULL;
467+
ExtensionString key = fileExt;
468+
BOOL result = FALSE;
469+
ULONG regKey(REG_SZ);
470+
471+
if (fileExt.empty())
472+
return false;
473+
474+
if (fileExt[0] != '.')
475+
key = L"." + fileExt;
476+
477+
key = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\" + key + L"\\UserChoice";
478+
479+
if (::RegOpenKeyEx(HKEY_CURRENT_USER, key.c_str(), 0, KEY_QUERY_VALUE, &extKey) == ERROR_SUCCESS)
480+
{
481+
TCHAR editorPath[255];
482+
ULONG fTypeSize = 255;
483+
484+
if (::RegQueryValueEx(extKey, L"Progid", NULL, &regKey, (LPBYTE)editorPath, &fTypeSize) == ERROR_SUCCESS)
485+
{
486+
result = ResolveAppPathFromProgID(editorPath, appPath);
487+
488+
}
489+
490+
::RegCloseKey(extKey);
491+
}
492+
493+
return result;
494+
}
495+
496+
497+
BOOL GetLegacyWin32SystemEditor(const ExtensionString& fileExt, ExtensionString &appPath)
498+
{
499+
HKEY rootKey;
500+
ULONG regKey(REG_SZ);
501+
ExtensionString key = fileExt;
502+
503+
if (fileExt.empty())
504+
return false;
505+
506+
if (fileExt[0] != '.')
507+
key = L"." + key;
508+
509+
// find the key for the file extension
510+
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, key.c_str(), 0, KEY_QUERY_VALUE, &rootKey) == ERROR_SUCCESS)
511+
{
512+
TCHAR nextKeyStr[255];
513+
ULONG strSize = 255;
514+
// get the value of the key
515+
if (RegQueryValueEx(rootKey, L"", NULL, &regKey,
516+
(LPBYTE)nextKeyStr, &strSize) == ERROR_SUCCESS)
517+
{
518+
RegCloseKey(rootKey);
519+
return ResolveAppPathFromProgID(nextKeyStr, appPath);
520+
}
521+
RegCloseKey(rootKey);
522+
}
523+
524+
key = key + L"\\OpenWithProgids";
525+
HKEY extKey;
526+
// find the key for the file extension
527+
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, key.c_str(), 0, KEY_QUERY_VALUE | KEY_READ, &extKey) == ERROR_SUCCESS)
528+
{
529+
TCHAR subKeyStr[255];
530+
ULONG subKeySize = 255;
531+
DWORD index = 0;
532+
LONG err = RegEnumValue(extKey, index, subKeyStr, &subKeySize,
533+
0, 0, 0, NULL);
534+
if (err != ERROR_NO_MORE_ITEMS)
535+
{
536+
RegCloseKey(extKey);
537+
return ResolveAppPathFromProgID(subKeyStr, appPath);
538+
}
539+
540+
RegCloseKey(extKey);
541+
}
542+
543+
return FALSE;
544+
}
545+
546+
int32 getSystemDefaultApp(const ExtensionString& fileTypes, ExtensionString& fileTypesWithdefaultApp)
547+
{
548+
wchar_t* nextPtr;
549+
wchar_t delim[] = L",";
550+
std::vector<ExtensionString> extArray;
551+
ExtensionString separator = L"##";
552+
553+
wchar_t* token = std::wcstok((wchar_t*)fileTypes.c_str(), delim, &nextPtr);
554+
555+
while (token) {
556+
extArray.push_back(token);
557+
token = wcstok(NULL, delim, &nextPtr);
558+
}
559+
560+
for (std::vector<ExtensionString>::const_iterator it = extArray.begin(); it != extArray.end(); ++it) {
561+
ExtensionString appPath;
562+
BOOL result = GetShellDefaultOpenWithProgPath(*it, appPath);
563+
564+
if (!result)
565+
result = GetLegacyWin32SystemEditor(*it, appPath);
566+
567+
if (result)
568+
fileTypesWithdefaultApp = fileTypesWithdefaultApp + *it + separator + appPath + L",";
569+
}
570+
571+
return NO_ERROR;
572+
573+
}
574+
406575
int32 OpenURLInDefaultBrowser(ExtensionString url)
407576
{
408577
DWORD result = (DWORD)ShellExecute(NULL, L"open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);

0 commit comments

Comments
 (0)