/* Copyright (C) 2009 John Emmas This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if (defined(PLATFORM_WINDOWS) && !defined(COMPILER_CYGWIN)) #include #include #ifdef COMPILER_MSVC #pragma warning(disable:4996) #endif #else #include #endif #include #include #include namespace ARDOUR { //*************************************************************** // // placeholder_for_non_msvc_specific_function() // // Description // // Returns: // // On Success: // // On Failure: // /* LIBARDOUR_API char* LIBARDOUR_APICALLTYPE placeholder_for_non_msvc_specific_function() { char *pRet = buffer; return (pRet); } */ } // namespace ARDOUR #ifdef COMPILER_MSVC #include namespace ARDOUR { //*************************************************************** // // symlink() // // Emulates POSIX symlink() but creates a Windows shortcut. To // create a Windows shortcut the supplied shortcut name must end // in ".lnk" // Note that you can only create a shortcut in a folder for which // you have appropriate access rights. Note also that the folder // must already exist. If it doesn't exist or if you don't have // sufficient access rights to it, symlink() will generate an // error (in common with its POSIX counterpart). // // Returns: // // On Success: Zero // On Failure: -1 ('errno' will contain the specific error) // LIBARDOUR_API int LIBARDOUR_APICALLTYPE symlink(const char *dest, const char *shortcut, const char *working_directory /*= NULL */) { IShellLinkA *pISL = NULL; IPersistFile *ppf = NULL; int ret = (-1); if ((NULL == dest) || (NULL == shortcut) || (strlen(shortcut) < 5) || (strlen(dest) == 0)) _set_errno(EINVAL); else if ((strlen(shortcut) > _MAX_PATH) || (strlen(dest) > _MAX_PATH)) _set_errno(ENAMETOOLONG); else if (Glib::file_test(shortcut, Glib::FILE_TEST_EXISTS)) _set_errno(EEXIST); else { HRESULT hRet = 0; if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL))) { if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) { char sc_path_lower_case[_MAX_PATH]; WCHAR shortcut_path[_MAX_PATH]; // Fail if the path isn't a shortcut strcpy(sc_path_lower_case, shortcut); strlwr(sc_path_lower_case); const char *p = strlen(sc_path_lower_case) + sc_path_lower_case - 4; if (0 == strcmp(p, ".lnk")) { HRESULT hr; // We're apparently been given valid Windows shortcut name MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH); // Create the shortcut if (FAILED (hr = ppf->Load(shortcut_path, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE))) hr = ppf->Save(shortcut_path, TRUE); if (S_OK == hr) { // Set its target path if (S_OK == pISL->SetPath(dest)) { // Set its working directory if (working_directory) p = working_directory; else p = ""; if (S_OK == pISL->SetWorkingDirectory(p)) { // Set its 'Show' command if (S_OK == pISL->SetShowCmd(SW_SHOWNORMAL)) { // And finally, set its icon to the same file as the target. // For the time being, don't fail if the target has no icon. if (Glib::file_test(dest, Glib::FILE_TEST_IS_DIR)) pISL->SetIconLocation("%SystemRoot%\\system32\\shell32.dll", 1); else pISL->SetIconLocation(dest, 0); if (S_OK == ppf->Save(shortcut_path, FALSE)) { Sleep(1500); ret = 0; // _set_errno(0); } else _set_errno(EACCES); } else _set_errno(EACCES); } else _set_errno(EACCES); } else _set_errno(EACCES); } else _set_errno(EBADF); } else _set_errno(EACCES); } else _set_errno(EBADF); } else { if (E_POINTER == hRet) _set_errno(EINVAL); else _set_errno(EIO); } } return (ret); } //*************************************************************** // // readlink() // // Emulates POSIX readlink() but using Windows shortcuts // Doesn't (currently) resolve shortcuts to shortcuts. This would // be quite simple to incorporate but we'd need to check for // recursion (i.e. a shortcut that points to an earlier shortcut // in the same chain). // // Returns: // // On Success: Zero // On Failure: -1 ('errno' will contain the specific error) // LIBARDOUR_API int LIBARDOUR_APICALLTYPE readlink(const char *__restrict shortcut, char *__restrict buf, size_t bufsize) { IShellLinkA *pISL = NULL; IPersistFile *ppf = NULL; int ret = (-1); if ((NULL == shortcut) || (NULL == buf) || (strlen(shortcut) < 5) || (bufsize == 0)) _set_errno(EINVAL); else if ((bufsize > _MAX_PATH) || (strlen(shortcut) > _MAX_PATH)) _set_errno(ENAMETOOLONG); else { HRESULT hRet = 0; if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL))) { if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) { char target_path[_MAX_PATH]; WCHAR shortcut_path[_MAX_PATH]; // Fail if the path isn't a shortcut strcpy(target_path, shortcut); // Use 'target_path' temporarily strlwr(target_path); const char *p = strlen(target_path) + target_path - 4; if (0 == strcmp(p, ".lnk")) { // We're apparently pointing to a valid Windows shortcut MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH); // Load the shortcut into our persistent file if (SUCCEEDED (ppf->Load(shortcut_path, 0))) { // Read the target information from the shortcut object if (S_OK == (pISL->GetPath (target_path, _MAX_PATH, NULL, SLGP_UNCPRIORITY))) { strncpy(buf, target_path, bufsize); ret = ((ret = strlen(buf)) > bufsize) ? bufsize : ret; // _set_errno(0); } else _set_errno(EACCES); } else _set_errno(EBADF); } else _set_errno(EINVAL); } else _set_errno(EBADF); } else { if (E_POINTER == hRet) _set_errno(EINVAL); else _set_errno(EIO); } if (ppf) ppf->Release(); if (pISL) pISL->Release(); } return (ret); } } // namespace ARDOUR #endif // COMPILER_MSVC