1 /**
2  * \file
3  * Windows icall support.
4  *
5  * Copyright 2016 Microsoft
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8 #include <config.h>
9 #include <glib.h>
10 
11 #if defined(HOST_WIN32)
12 #include <winsock2.h>
13 #include <windows.h>
14 #include "mono/metadata/icall-windows-internals.h"
15 
16 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
17 #include <shlobj.h>
18 #endif
19 
20 void
mono_icall_make_platform_path(gchar * path)21 mono_icall_make_platform_path (gchar *path)
22 {
23 	for (size_t i = strlen (path); i > 0; i--)
24 		if (path [i-1] == '\\')
25 			path [i-1] = '/';
26 }
27 
28 const gchar *
mono_icall_get_file_path_prefix(const gchar * path)29 mono_icall_get_file_path_prefix (const gchar *path)
30 {
31 	if (*path == '/' && *(path + 1) == '/') {
32 		return "file:";
33 	} else {
34 		return "file:///";
35 	}
36 }
37 
38 gpointer
mono_icall_module_get_hinstance(MonoReflectionModuleHandle module)39 mono_icall_module_get_hinstance (MonoReflectionModuleHandle module)
40 {
41 	MonoImage *image = MONO_HANDLE_GETVAL (module, image);
42 	if (image && image->is_module_handle)
43 		return image->raw_data;
44 
45 	return (gpointer) (-1);
46 }
47 
48 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
49 MonoStringHandle
mono_icall_get_machine_name(MonoError * error)50 mono_icall_get_machine_name (MonoError *error)
51 {
52 	gunichar2 *buf;
53 	guint32 len;
54 	MonoStringHandle result;
55 
56 	len = MAX_COMPUTERNAME_LENGTH + 1;
57 	buf = g_new (gunichar2, len);
58 
59 	result = NULL;
60 	if (GetComputerName (buf, (PDWORD) &len)) {
61 		result = mono_string_new_utf16_handle (mono_domain_get (), buf, len, error);
62 	} else
63 		result = MONO_HANDLE_NEW (MonoString, NULL);
64 
65 	g_free (buf);
66 	return result;
67 }
68 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
69 
70 int
mono_icall_get_platform(void)71 mono_icall_get_platform (void)
72 {
73 	/* Win32NT */
74 	return 2;
75 }
76 
77 MonoStringHandle
mono_icall_get_new_line(MonoError * error)78 mono_icall_get_new_line (MonoError *error)
79 {
80 	error_init (error);
81 	return mono_string_new_handle (mono_domain_get (), "\r\n", error);
82 }
83 
84 MonoBoolean
mono_icall_is_64bit_os(void)85 mono_icall_is_64bit_os (void)
86 {
87 #if SIZEOF_VOID_P == 8
88 	return TRUE;
89 #else
90 	gboolean isWow64Process = FALSE;
91 	if (IsWow64Process (GetCurrentProcess (), &isWow64Process)) {
92 		return (MonoBoolean)isWow64Process;
93 	}
94 	return FALSE;
95 #endif
96 }
97 
98 MonoArray *
mono_icall_get_environment_variable_names(MonoError * error)99 mono_icall_get_environment_variable_names (MonoError *error)
100 {
101 	MonoArray *names;
102 	MonoDomain *domain;
103 	MonoString *str;
104 	WCHAR* env_strings;
105 	WCHAR* env_string;
106 	WCHAR* equal_str;
107 	int n = 0;
108 
109 	error_init (error);
110 	env_strings = GetEnvironmentStrings();
111 
112 	if (env_strings) {
113 		env_string = env_strings;
114 		while (*env_string != '\0') {
115 		/* weird case that MS seems to skip */
116 			if (*env_string != '=')
117 				n++;
118 			while (*env_string != '\0')
119 				env_string++;
120 			env_string++;
121 		}
122 	}
123 
124 	domain = mono_domain_get ();
125 	names = mono_array_new_checked (domain, mono_defaults.string_class, n, error);
126 	return_val_if_nok (error, NULL);
127 
128 	if (env_strings) {
129 		n = 0;
130 		env_string = env_strings;
131 		while (*env_string != '\0') {
132 			/* weird case that MS seems to skip */
133 			if (*env_string != '=') {
134 				equal_str = wcschr(env_string, '=');
135 				g_assert(equal_str);
136 				str = mono_string_new_utf16_checked (domain, env_string, (gint32)(equal_str - env_string), error);
137 				goto_if_nok (error, cleanup);
138 
139 				mono_array_setref (names, n, str);
140 				n++;
141 			}
142 			while (*env_string != '\0')
143 				env_string++;
144 			env_string++;
145 		}
146 
147 	}
148 
149 cleanup:
150 	if (env_strings)
151 		FreeEnvironmentStrings (env_strings);
152 	if (!is_ok (error))
153 		return NULL;
154 	return names;
155 }
156 
157 void
mono_icall_set_environment_variable(MonoString * name,MonoString * value)158 mono_icall_set_environment_variable (MonoString *name, MonoString *value)
159 {
160 	gunichar2 *utf16_name, *utf16_value;
161 
162 	utf16_name = mono_string_to_utf16 (name);
163 	if ((value == NULL) || (mono_string_length (value) == 0) || (mono_string_chars (value)[0] == 0)) {
164 		SetEnvironmentVariable (utf16_name, NULL);
165 		g_free (utf16_name);
166 		return;
167 	}
168 
169 	utf16_value = mono_string_to_utf16 (value);
170 
171 	SetEnvironmentVariable (utf16_name, utf16_value);
172 
173 	g_free (utf16_name);
174 	g_free (utf16_value);
175 }
176 
177 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
178 MonoStringHandle
mono_icall_get_windows_folder_path(int folder,MonoError * error)179 mono_icall_get_windows_folder_path (int folder, MonoError *error)
180 {
181 	error_init (error);
182 	#ifndef CSIDL_FLAG_CREATE
183 		#define CSIDL_FLAG_CREATE	0x8000
184 	#endif
185 
186 	WCHAR path [MAX_PATH];
187 	/* Create directory if no existing */
188 	if (SUCCEEDED (SHGetFolderPathW (NULL, folder | CSIDL_FLAG_CREATE, NULL, 0, path))) {
189 		int len = 0;
190 		while (path [len])
191 			++ len;
192 		return mono_string_new_utf16_handle (mono_domain_get (), path, len, error);
193 	}
194 	return mono_string_new_handle (mono_domain_get (), "", error);
195 }
196 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
197 
198 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
199 MonoBoolean
mono_icall_broadcast_setting_change(MonoError * error)200 mono_icall_broadcast_setting_change (MonoError *error)
201 {
202 	error_init (error);
203 	SendMessageTimeout (HWND_BROADCAST, WM_SETTINGCHANGE, (WPARAM)NULL, (LPARAM)L"Environment", SMTO_ABORTIFHUNG, 2000, 0);
204 	return TRUE;
205 }
206 
207 gint32
mono_icall_wait_for_input_idle(gpointer handle,gint32 milliseconds)208 mono_icall_wait_for_input_idle (gpointer handle, gint32 milliseconds)
209 {
210 	return WaitForInputIdle (handle, milliseconds);
211 }
212 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
213 
214 void
mono_icall_write_windows_debug_string(MonoString * message)215 mono_icall_write_windows_debug_string (MonoString *message)
216 {
217 	OutputDebugString (mono_string_chars (message));
218 }
219 
220 #endif /* HOST_WIN32 */
221