ardour
msvc_libardour.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 John Emmas
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #if (defined(PLATFORM_WINDOWS) && !defined(COMPILER_CYGWIN))
21 #include <shlobj.h>
22 #include <glibmm.h>
23 #ifdef COMPILER_MSVC
24 #pragma warning(disable:4996)
25 #endif
26 #else
27 #include <glib.h>
28 #endif
29 
30 #include <string.h>
31 #include <stdlib.h>
32 #include <ardour/msvc_libardour.h>
33 
34 namespace ARDOUR {
35 
36 //***************************************************************
37 //
38 // placeholder_for_non_msvc_specific_function()
39 //
40 // Description
41 //
42 // Returns:
43 //
44 // On Success:
45 //
46 // On Failure:
47 //
48 /* LIBARDOUR_API char* LIBARDOUR_APICALLTYPE
49  placeholder_for_non_msvc_specific_function()
50 {
51 char *pRet = buffer;
52 
53  return (pRet);
54 }
55 */
56 
57 } // namespace ARDOUR
58 
59 #ifdef COMPILER_MSVC
60 
61 #include <errno.h>
62 
63 namespace ARDOUR {
64 
65 //***************************************************************
66 //
67 // symlink()
68 //
69 // Emulates POSIX symlink() but creates a Windows shortcut. To
70 // create a Windows shortcut the supplied shortcut name must end
71 // in ".lnk"
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).
77 //
78 // Returns:
79 //
80 // On Success: Zero
81 // On Failure: -1 ('errno' will contain the specific error)
82 //
84 symlink(const char *dest, const char *shortcut, const char *working_directory /*= NULL */)
85 {
86 IShellLinkA *pISL = NULL;
87 IPersistFile *ppf = NULL;
88 int ret = (-1);
89 
90  if ((NULL == dest) || (NULL == shortcut) || (strlen(shortcut) < 5) || (strlen(dest) == 0))
91  _set_errno(EINVAL);
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))
95  _set_errno(EEXIST);
96  else
97  {
98  HRESULT hRet = 0;
99 
100  if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
101  {
102  if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
103  {
104  char sc_path_lower_case[_MAX_PATH];
105  WCHAR shortcut_path[_MAX_PATH];
106 
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;
111 
112  if (0 == strcmp(p, ".lnk"))
113  {
114  HRESULT hr;
115 
116  // We're apparently been given valid Windows shortcut name
117  MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
118 
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);
122 
123  if (S_OK == hr)
124  {
125  // Set its target path
126  if (S_OK == pISL->SetPath(dest))
127  {
128  // Set its working directory
129  if (working_directory)
130  p = working_directory;
131  else
132  p = "";
133 
134  if (S_OK == pISL->SetWorkingDirectory(p))
135  {
136  // Set its 'Show' command
137  if (S_OK == pISL->SetShowCmd(SW_SHOWNORMAL))
138  {
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);
143  else
144  pISL->SetIconLocation(dest, 0);
145 
146  if (S_OK == ppf->Save(shortcut_path, FALSE))
147  {
148  Sleep(1500);
149 
150  ret = 0;
151  // _set_errno(0);
152  }
153  else
154  _set_errno(EACCES);
155  }
156  else
157  _set_errno(EACCES);
158  }
159  else
160  _set_errno(EACCES);
161  }
162  else
163  _set_errno(EACCES);
164  }
165  else
166  _set_errno(EBADF);
167  }
168  else
169  _set_errno(EACCES);
170  }
171  else
172  _set_errno(EBADF);
173  }
174  else
175  {
176  if (E_POINTER == hRet)
177  _set_errno(EINVAL);
178  else
179  _set_errno(EIO);
180  }
181  }
182 
183  return (ret);
184 }
185 
186 
187 //***************************************************************
188 //
189 // readlink()
190 //
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).
196 //
197 // Returns:
198 //
199 // On Success: Zero
200 // On Failure: -1 ('errno' will contain the specific error)
201 //
203 readlink(const char *__restrict shortcut, char *__restrict buf, size_t bufsize)
204 {
205 IShellLinkA *pISL = NULL;
206 IPersistFile *ppf = NULL;
207 int ret = (-1);
208 
209  if ((NULL == shortcut) || (NULL == buf) || (strlen(shortcut) < 5) || (bufsize == 0))
210  _set_errno(EINVAL);
211  else if ((bufsize > _MAX_PATH) || (strlen(shortcut) > _MAX_PATH))
212  _set_errno(ENAMETOOLONG);
213  else
214  {
215  HRESULT hRet = 0;
216 
217  if (SUCCEEDED (hRet = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
218  {
219  if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
220  {
221  char target_path[_MAX_PATH];
222  WCHAR shortcut_path[_MAX_PATH];
223 
224  // Fail if the path isn't a shortcut
225  strcpy(target_path, shortcut); // Use 'target_path' temporarily
226  strlwr(target_path);
227  const char *p = strlen(target_path) + target_path - 4;
228 
229  if (0 == strcmp(p, ".lnk"))
230  {
231  // We're apparently pointing to a valid Windows shortcut
232  MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut, -1, shortcut_path, _MAX_PATH);
233 
234  // Load the shortcut into our persistent file
235  if (SUCCEEDED (ppf->Load(shortcut_path, 0)))
236  {
237  // Read the target information from the shortcut object
238  if (S_OK == (pISL->GetPath (target_path, _MAX_PATH, NULL, SLGP_UNCPRIORITY)))
239  {
240  strncpy(buf, target_path, bufsize);
241  ret = ((ret = strlen(buf)) > bufsize) ? bufsize : ret;
242  // _set_errno(0);
243  }
244  else
245  _set_errno(EACCES);
246  }
247  else
248  _set_errno(EBADF);
249  }
250  else
251  _set_errno(EINVAL);
252  }
253  else
254  _set_errno(EBADF);
255  }
256  else
257  {
258  if (E_POINTER == hRet)
259  _set_errno(EINVAL);
260  else
261  _set_errno(EIO);
262  }
263 
264  if (ppf)
265  ppf->Release();
266 
267  if (pISL)
268  pISL->Release();
269  }
270 
271  return (ret);
272 }
273 
274 } // namespace ARDOUR
275 
276 #endif // COMPILER_MSVC
#define LIBARDOUR_APICALLTYPE
#define _MAX_PATH
Definition: amp.h:29
#define LIBARDOUR_API