Merge pull request #3948 from techee/warning_fix2
[geany-mirror.git] / src / win32.c
bloba96473a2a1e8ed3cc66db4dc960662572764d2dd
1 /*
2 * win32.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2005 The Geany contributors
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Special functions for the win32 platform, to provide native dialogs.
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 /* Need Windows XP for SHGetFolderPathAndSubDirW */
30 #define _WIN32_WINNT 0x0501
31 /* Needed for SHGFP_TYPE */
32 #define _WIN32_IE 0x0500
34 #include "win32.h"
36 #ifdef G_OS_WIN32
38 #include "dialogs.h"
39 #include "document.h"
40 #include "editor.h"
41 #include "filetypes.h"
42 #include "project.h"
43 #include "support.h"
44 #include "ui_utils.h"
45 #include "utils.h"
47 #include <ctype.h>
48 #include <fcntl.h>
49 #include <io.h>
50 #include <math.h>
51 #include <stdlib.h>
52 #include <string.h>
54 #include <windows.h>
55 #include <commdlg.h>
56 #include <shellapi.h>
57 #include <shlobj.h>
59 #include <glib/gstdio.h>
60 #include <gdk/gdkwin32.h>
63 /* Little wrapper for _waccess(), returns errno or 0 if there was no error */
64 gint win32_check_write_permission(const gchar *dir)
66 static wchar_t w_dir[MAX_PATH];
67 MultiByteToWideChar(CP_UTF8, 0, dir, -1, w_dir, G_N_ELEMENTS(w_dir));
68 if (_waccess(w_dir, R_OK | W_OK) != 0)
69 return errno;
70 else
71 return 0;
75 /* Just a simple wrapper function to open a browser window */
76 void win32_open_browser(const gchar *uri)
78 gint ret;
79 if (strncmp(uri, "file://", 7) == 0)
81 uri += 7;
82 if (strchr(uri, ':') != NULL)
84 while (*uri == '/')
85 uri++;
88 ret = (gint) ShellExecute(NULL, "open", uri, NULL, NULL, SW_SHOWNORMAL);
89 if (ret <= 32)
91 gchar *err = g_win32_error_message(GetLastError());
92 ui_set_statusbar(TRUE, _("Failed to open URI \"%s\": %s"), uri, err);
93 g_warning("ShellExecute failed opening \"%s\" (code %d): %s", uri, ret, err);
94 g_free(err);
99 static FILE *open_std_handle(DWORD handle, const char *mode)
101 HANDLE lStdHandle;
102 int hConHandle;
103 FILE *fp;
105 lStdHandle = GetStdHandle(handle);
106 if (lStdHandle == INVALID_HANDLE_VALUE)
108 gchar *err = g_win32_error_message(GetLastError());
109 g_warning("GetStdHandle(%ld) failed: %s", (long)handle, err);
110 g_free(err);
111 return NULL;
113 hConHandle = _open_osfhandle((intptr_t)lStdHandle, _O_TEXT);
114 if (hConHandle == -1)
116 gchar *err = g_win32_error_message(GetLastError());
117 g_warning("_open_osfhandle(handle(%ld), _O_TEXT) failed: %s", (long)handle, err);
118 g_free(err);
119 return NULL;
121 fp = _fdopen(hConHandle, mode);
122 if (! fp)
124 gchar *err = g_win32_error_message(GetLastError());
125 g_warning("_fdopen(%d, \"%s\") failed: %s", hConHandle, mode, err);
126 g_free(err);
127 return NULL;
129 if (setvbuf(fp, NULL, _IONBF, 0) != 0)
131 gchar *err = g_win32_error_message(GetLastError());
132 g_warning("setvbuf(%p, NULL, _IONBF, 0) failed: %s", fp, err);
133 g_free(err);
134 fclose(fp);
135 return NULL;
138 return fp;
142 static void debug_setup_console(void)
144 static const WORD MAX_CONSOLE_LINES = 500;
145 CONSOLE_SCREEN_BUFFER_INFO coninfo;
146 FILE *fp;
148 /* allocate a console for this app */
149 AllocConsole();
151 /* set the screen buffer to be big enough to let us scroll text */
152 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
153 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
154 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
156 /* redirect unbuffered STDOUT to the console */
157 fp = open_std_handle(STD_OUTPUT_HANDLE, "w");
158 if (fp)
159 *stdout = *fp;
161 /* redirect unbuffered STDERR to the console */
162 fp = open_std_handle(STD_ERROR_HANDLE, "w");
163 if (fp)
164 *stderr = *fp;
166 /* redirect unbuffered STDIN to the console */
167 fp = open_std_handle(STD_INPUT_HANDLE, "r");
168 if (fp)
169 *stdin = *fp;
173 void win32_init_debug_code(void)
175 if (app->debug_mode)
177 /* create a console window to get log messages on Windows,
178 * especially useful when generating tags files */
179 debug_setup_console();
184 /* expands environment placeholders in @str. input and output is in UTF-8 */
185 gchar *win32_expand_environment_variables(const gchar *str)
187 wchar_t *cmdline = g_utf8_to_utf16(str, -1, NULL, NULL, NULL);
188 wchar_t expCmdline[32768]; /* 32768 is the limit for ExpandEnvironmentStrings() */
189 gchar *expanded = NULL;
191 if (cmdline && ExpandEnvironmentStringsW(cmdline, expCmdline, sizeof(expCmdline)) != 0)
192 expanded = g_utf16_to_utf8(expCmdline, -1, NULL, NULL, NULL);
194 g_free(cmdline);
196 return expanded ? expanded : g_strdup(str);
200 /* From GDK (they got it from MS Knowledge Base article Q130698) */
201 static gboolean resolve_link(HWND hWnd, wchar_t *link, gchar **lpszPath)
203 WIN32_FILE_ATTRIBUTE_DATA wfad;
204 HRESULT hres;
205 IShellLinkW *pslW = NULL;
206 IPersistFile *ppf = NULL;
207 LPVOID pslWV = NULL;
208 LPVOID ppfV = NULL;
210 /* Check if the file is empty first because IShellLink::Resolve for some reason succeeds
211 * with an empty file and returns an empty "link target". (#524151) */
212 if (!GetFileAttributesExW(link, GetFileExInfoStandard, &wfad) ||
213 (wfad.nFileSizeHigh == 0 && wfad.nFileSizeLow == 0))
215 return FALSE;
218 /* Assume failure to start with: */
219 *lpszPath = 0;
221 CoInitialize(NULL);
223 hres = CoCreateInstance(
224 &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, &pslWV);
226 if (SUCCEEDED(hres))
228 /* The IShellLink interface supports the IPersistFile interface.
229 * Get an interface pointer to it. */
230 pslW = (IShellLinkW*) pslWV;
231 hres = pslW->lpVtbl->QueryInterface(pslW, &IID_IPersistFile, &ppfV);
234 if (SUCCEEDED(hres))
236 /* Load the file. */
237 ppf = (IPersistFile*) ppfV;
238 hres = ppf->lpVtbl->Load(ppf, link, STGM_READ);
241 if (SUCCEEDED(hres))
243 /* Resolve the link by calling the Resolve() interface function. */
244 hres = pslW->lpVtbl->Resolve(pslW, hWnd, SLR_ANY_MATCH | SLR_NO_UI);
247 if (SUCCEEDED(hres))
249 wchar_t wtarget[MAX_PATH];
251 hres = pslW->lpVtbl->GetPath(pslW, wtarget, MAX_PATH, NULL, 0);
252 if (SUCCEEDED(hres))
253 *lpszPath = g_utf16_to_utf8(wtarget, -1, NULL, NULL, NULL);
256 if (ppf)
257 ppf->lpVtbl->Release(ppf);
259 if (pslW)
260 pslW->lpVtbl->Release(pslW);
262 return SUCCEEDED(hres);
266 /* Checks whether file_name is a Windows shortcut. file_name is expected in UTF-8 encoding.
267 * If file_name is a Windows shortcut, it returns the target in UTF-8 encoding.
268 * If it is not a shortcut, it returns a newly allocated copy of file_name. */
269 gchar *win32_get_shortcut_target(const gchar *file_name)
271 gchar *path = NULL;
272 wchar_t *wfilename = g_utf8_to_utf16(file_name, -1, NULL, NULL, NULL);
273 HWND hWnd = NULL;
275 if (main_widgets.window != NULL)
277 GdkWindow *window = gtk_widget_get_window(main_widgets.window);
278 if (window != NULL)
279 hWnd = GDK_WINDOW_HWND(window);
282 resolve_link(hWnd, wfilename, &path);
283 g_free(wfilename);
285 if (path == NULL)
286 return g_strdup(file_name);
287 else
288 return path;
292 void win32_set_working_directory(const gchar *dir)
294 SetCurrentDirectory(dir);
298 gchar *win32_get_installation_dir(void)
300 return g_win32_get_package_installation_directory_of_module(NULL);
304 gchar *win32_get_user_config_dir(void)
306 HRESULT hr;
307 wchar_t path[MAX_PATH];
309 hr = SHGetFolderPathAndSubDirW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, L"geany", path);
310 if (SUCCEEDED(hr))
312 // GLib always uses UTF-8 for filename encoding on Windows
313 int u8_size = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
314 if (u8_size > 0)
316 gchar *u8_path = g_malloc0(u8_size + 1);
317 if (u8_path != NULL &&
318 WideCharToMultiByte(CP_UTF8, 0, path, -1, u8_path, u8_size, NULL, NULL))
320 return u8_path;
325 // glib fallback
326 g_warning("Failed to retrieve Windows config dir, falling back to default");
327 return g_build_filename(g_get_user_config_dir(), "geany", NULL);
330 #endif