2 Copyright (C) 2009 John Emmas
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #if (defined(PLATFORM_WINDOWS) && !defined(COMPILER_CYGWIN))
24 #pragma warning(disable:4996)
32 #include <ardour/msvc_libardour.h>
36 //***************************************************************
38 // placeholder_for_non_msvc_specific_function()
48 /* LIBARDOUR_API char* LIBARDOUR_APICALLTYPE
49 placeholder_for_non_msvc_specific_function()
65 //***************************************************************
69 // Emulates POSIX symlink() but creates a Windows shortcut. To
70 // create a Windows shortcut the supplied shortcut name must end
72 // Note that you can only create a shortcut in a folder for which
73 // you have appropriate access rights. Note also that the folder
74 // must already exist. If it doesn't exist or if you don't have
75 // sufficient access rights to it, symlink() will generate an
76 // error (in common with its POSIX counterpart).
81 // On Failure: -1 ('errno' will contain the specific error)
83 LIBARDOUR_API int LIBARDOUR_APICALLTYPE
84 symlink(const char *dest, const char *shortcut, const char *working_directory /*= NULL */)
86 IShellLinkA *pISL = NULL;
87 IPersistFile *ppf = NULL;
90 if ((NULL == dest) || (NULL == shortcut) || (strlen(shortcut) < 5) || (strlen(dest) == 0))
92 else if ((strlen(shortcut) > _MAX_PATH) || (strlen(dest) > _MAX_PATH))
93 _set_errno(ENAMETOOLONG);
94 else if (Glib::file_test(shortcut, Glib::FILE_TEST_EXISTS))
100 if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
102 if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
104 char sc_path_lower_case[_MAX_PATH];
105 WCHAR shortcut_path[_MAX_PATH];
107 // Fail if the path isn't a shortcut
108 strcpy(sc_path_lower_case, shortcut);
109 strlwr(sc_path_lower_case);
110 const char *p = strlen(sc_path_lower_case) + sc_path_lower_case - 4;
112 if (0 == strcmp(p, ".lnk"))
116 // We're apparently been given valid Windows shortcut name
117 MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
119 // Create the shortcut
120 if (FAILED (hr = ppf->Load(shortcut_path, STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE)))
121 hr = ppf->Save(shortcut_path, TRUE);
125 // Set its target path
126 if (S_OK == pISL->SetPath(dest))
128 // Set its working directory
129 if (working_directory)
130 p = working_directory;
134 if (S_OK == pISL->SetWorkingDirectory(p))
136 // Set its 'Show' command
137 if (S_OK == pISL->SetShowCmd(SW_SHOWNORMAL))
139 // And finally, set its icon to the same file as the target.
140 // For the time being, don't fail if the target has no icon.
141 if (Glib::file_test(dest, Glib::FILE_TEST_IS_DIR))
142 pISL->SetIconLocation("%SystemRoot%\\system32\\shell32.dll", 1);
144 pISL->SetIconLocation(dest, 0);
146 if (S_OK == ppf->Save(shortcut_path, FALSE))
176 if (E_POINTER == hRet)
187 //***************************************************************
191 // Emulates POSIX readlink() but using Windows shortcuts
192 // Doesn't (currently) resolve shortcuts to shortcuts. This would
193 // be quite simple to incorporate but we'd need to check for
194 // recursion (i.e. a shortcut that points to an earlier shortcut
195 // in the same chain).
200 // On Failure: -1 ('errno' will contain the specific error)
202 LIBARDOUR_API int LIBARDOUR_APICALLTYPE
203 readlink(const char *__restrict shortcut, char *__restrict buf, size_t bufsize)
205 IShellLinkA *pISL = NULL;
206 IPersistFile *ppf = NULL;
209 if ((NULL == shortcut) || (NULL == buf) || (strlen(shortcut) < 5) || (bufsize == 0))
211 else if ((bufsize > _MAX_PATH) || (strlen(shortcut) > _MAX_PATH))
212 _set_errno(ENAMETOOLONG);
217 if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
219 if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
221 char target_path[_MAX_PATH];
222 WCHAR shortcut_path[_MAX_PATH];
224 // Fail if the path isn't a shortcut
225 strcpy(target_path, shortcut); // Use 'target_path' temporarily
227 const char *p = strlen(target_path) + target_path - 4;
229 if (0 == strcmp(p, ".lnk"))
231 // We're apparently pointing to a valid Windows shortcut
232 MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
234 // Load the shortcut into our persistent file
235 if (SUCCEEDED (ppf->Load(shortcut_path, 0)))
237 // Read the target information from the shortcut object
238 if (S_OK == (pISL->GetPath (target_path, _MAX_PATH, NULL, SLGP_UNCPRIORITY)))
240 strncpy(buf, target_path, bufsize);
241 ret = ((ret = strlen(buf)) > bufsize) ? bufsize : ret;
258 if (E_POINTER == hRet)
274 } // namespace ARDOUR
276 #endif // COMPILER_MSVC