add more spacing
[personal-kdebase.git] / runtime / platforms / win / kwinstartmenu / linkfile.cpp
blobd0d759914e346a3b41ecbd4613f22f62072df553
1 /* This file is part of the KDE project
3 Copyright (C) 2006-2008 Ralf Habacker <ralf.habacker@freenet.de>
4 All rights reserved.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
21 #include "linkfile.h"
23 #include <windows.h>
24 #include <windowsx.h>
25 #include <objbase.h>
26 #include <shlobj.h>
27 #include <shlwapi.h>
28 #include <initguid.h>
30 #include <QDir>
31 #include <QFile>
33 #include <KDebug>
34 #include <kstandarddirs.h>
35 #include <kservicegroup.h>
36 // required by kdesktopfile.h -> should be in kdesktopfile.h
37 #include <kconfiggroup.h>
38 #include <kdesktopfile.h>
40 #if defined(_MSC_VER)
41 #define MY_CAST(a) a
42 #else
43 // mingw needs char cast
44 #define MY_CAST(a) (CHAR *)(a)
45 #endif
48 add correct prefix for win32 filesystem functions
49 described in msdn, but taken from Qt's qfsfileeninge_win.cpp
51 static QString longFileName(const QString &path)
53 QString absPath = QDir::convertSeparators(path);
54 QString prefix = QLatin1String("\\\\?\\");
55 if (path.startsWith("//") || path.startsWith("\\\\")) {
56 prefix = QLatin1String("\\\\?\\UNC\\");
57 absPath.remove(0, 2);
59 return prefix + absPath;
62 bool LinkFile::read()
64 LPCWSTR szShortcutFile = (LPCWSTR)m_linkPath.utf16();
65 WCHAR szTarget[MAX_PATH];
66 WCHAR szWorkingDir[MAX_PATH];
67 WCHAR szDescription[MAX_PATH];
68 WCHAR szArguments[MAX_PATH];
70 IShellLink* psl = NULL;
71 IPersistFile* ppf = NULL;
72 bool bResult = false;
74 # if !defined(UNICODE)
75 WCHAR wsz[MAX_PATH];
76 if (0 == MultiByteToWideChar(CP_ACP, 0, MY_CAST(szShortcutFile), -1, wsz, MAX_PATH) )
77 goto cleanup;
78 # else
79 LPCWSTR wsz = szShortcutFile;
80 # endif
82 if (FAILED( CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl) ))
83 goto cleanup;
85 if (FAILED( psl->QueryInterface(IID_IPersistFile, (void **) &ppf) ))
86 goto cleanup;
88 if (FAILED( ppf->Load(wsz, STGM_READ) ))
89 goto cleanup;
91 if (NOERROR != psl->GetPath(MY_CAST(szTarget), MAX_PATH, NULL, 0) )
92 goto cleanup;
93 m_execPath = QString::fromUtf16((const ushort*)szTarget);
95 if (NOERROR != psl->GetWorkingDirectory(MY_CAST(szWorkingDir), MAX_PATH) )
96 goto cleanup;
97 m_workingDir = QString::fromUtf16((const ushort*)szWorkingDir);
99 if (NOERROR != psl->GetDescription(MY_CAST(szDescription), MAX_PATH) )
100 goto cleanup;
101 m_description = QString::fromUtf16((const ushort*)szDescription);
103 if (NOERROR != psl->GetArguments(MY_CAST(szArguments), MAX_PATH) )
104 goto cleanup;
105 m_arguments = QString::fromUtf16((const ushort*)szArguments).split(QLatin1Char(' '), QString::SkipEmptyParts);
107 bResult = true;
109 cleanup:
110 if (ppf) ppf->Release();
111 if (psl) psl->Release();
112 return bResult;
115 bool LinkFile::create()
117 HRESULT hres;
118 IShellLinkW* psl;
120 QString linkName = longFileName(m_linkPath);
122 LPCWSTR lpszPathObj = (LPCWSTR)m_execPath.utf16();
123 LPCWSTR lpszPathLink = (LPCWSTR)m_linkPath.utf16();
124 LPCWSTR lpszDesc = (LPCWSTR)m_description.utf16();
125 LPCWSTR lpszWorkDir = (LPCWSTR)m_workingDir.utf16();
126 // casting join directly results into a wrong lpszArguments
127 QString args = m_arguments.join(QLatin1String(" "));
128 LPCWSTR lpszArguments = (LPCWSTR)args.utf16();
130 CoInitialize(NULL);
131 // Get a pointer to the IShellLink interface.
132 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (LPVOID*)&psl);
134 if (SUCCEEDED(hres))
136 IPersistFile* ppf;
138 // Set the path to the shortcut target and add the description.
139 if(!SUCCEEDED(psl->SetPath(lpszPathObj))) {
140 kDebug() << "error setting path for link to " << m_execPath;
141 psl->Release();
142 return false;
144 if(!SUCCEEDED(psl->SetDescription(lpszDesc))) {
145 kDebug() << "error setting description for link to " << m_description;
146 psl->Release();
147 return false;
149 if(!SUCCEEDED(psl->SetWorkingDirectory(lpszWorkDir))) {
150 kDebug() << "error setting working Directory for link to " << m_workingDir;
151 psl->Release();
152 return false;
154 if(!m_arguments.isEmpty() && !SUCCEEDED(psl->SetArguments(lpszArguments))) {
155 kDebug() << "error setting arguments for link to " << m_arguments;
156 psl->Release();
157 return false;
160 // Query IShellLink for the IPersistFile interface for saving the
161 // shortcut in persistent storage.
162 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
164 if (SUCCEEDED(hres))
166 hres = ppf->Save(lpszPathLink, TRUE);
167 // Save the link by calling IPersistFile::Save.
168 if(!SUCCEEDED(hres))
169 kDebug() << "error saving link to " << linkName;
171 ppf->Release();
173 psl->Release();
174 } else {
175 kDebug() << "Error: Got no pointer to the IShellLink interface.";
177 CoUninitialize(); // cleanup COM after you're done using its services
178 return SUCCEEDED(hres) ? true : false;
181 bool LinkFile::remove()
183 bool ret = QFile::remove(m_linkPath);
184 QFileInfo fi(m_linkPath);
185 QDir d;
186 d.rmpath(fi.absolutePath());
187 return ret;
190 bool LinkFile::exists()
192 return QFile::exists(m_linkPath);
196 bool LinkFiles::scan(QList <LinkFile> &files, const QString &path)
198 QDir aDir(path);
199 bool has_err = false;
200 if (aDir.exists())//QDir::NoDotAndDotDot
202 QFileInfoList entries = aDir.entryInfoList(QDir::NoDotAndDotDot |
203 QDir::Dirs | QDir::Files);
204 int count = entries.size();
205 foreach(QFileInfo entryInfo, entries)
207 QString _path = entryInfo.absoluteFilePath();
208 if (entryInfo.isDir())
210 has_err = scan(files,_path);
212 else
214 if (_path.toLower().endsWith(".lnk"))
215 files.append(LinkFile("",_path,"",""));
219 return has_err;
222 bool LinkFiles::create(QList <LinkFile> &newFiles)
224 // create new link files
225 foreach(LinkFile linkFile, newFiles)
227 if (!linkFile.exists())
229 if (linkFile.create())
230 kDebug() << "created" << linkFile;
231 else
232 kDebug() << "failed to create" << linkFile;
235 return true;
238 bool LinkFiles::cleanup(QList <LinkFile> &newFiles, QList <LinkFile> &oldFiles)
240 // delete not available linkfiles
241 foreach(LinkFile oldFile, oldFiles)
243 QString oldPath = QDir::fromNativeSeparators ( oldFile.linkPath().toLower() );
244 bool found = false;
245 foreach(LinkFile newFile, newFiles)
247 QString newPath = QDir::fromNativeSeparators ( newFile.linkPath().toLower());
248 if (newPath == oldPath)
250 found = true;
251 break;
254 if (!found)
256 kDebug() << "deleted" << oldFile << oldFile.remove();
259 return true;
262 QDebug operator<<(QDebug out, const LinkFile &c)
264 out.space() << "LinkFile ("
265 << "linkPath" << c.m_linkPath
266 << "execPath" << c.m_execPath
267 << "arguments" << c.m_arguments
268 << "workingDir" << c.m_workingDir
269 << "description" << c.m_description
270 << ")";
271 return out;
274 // vim: ts=4 sw=4 et