#define MONO_DECL_CALLBACK(prefix, ret, name, sig) ret (*name) sig;
#define MONO_INIT_CALLBACK(prefix, ret, name, sig) prefix ## _ ## name,
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_module_filename (gpointer mod, gunichar2** pstr, guint32* plength);
+
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_module_filename_ex (gpointer process, gpointer mod, gunichar2** pstr, guint32* plength);
+
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_module_basename (gpointer process, gpointer mod, gunichar2** pstr, guint32* plength);
+
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_current_directory (gunichar2** pstr, guint32* plength);
+
// For each allocator; i.e. returning gpointer that needs to be cast.
// Macros do not recurse, so naming function and macro the same is ok.
// However these are also already macros.
gint32 buffer_size = 1024;
gint32 retval;
var = u8to16(variable);
- buffer = g_malloc(buffer_size*sizeof(gunichar2));
+ // FIXME This should loop in case another thread is growing the data.
+ buffer = g_new (gunichar2, buffer_size);
retval = GetEnvironmentVariableW (var, buffer, buffer_size);
if (retval != 0) {
if (retval > buffer_size) {
}
return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name);
}
+
+// This is not about GModule but is still a close fit.
+// This is not named "g_" but that should be ok.
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_module_filename (gpointer mod, gunichar2** pstr, guint32* plength)
+{
+ gunichar2* str = NULL;
+ guint32 capacity = 32; // tunable
+ guint32 length = 0;
+ gboolean success = FALSE;
+
+ while (TRUE)
+ {
+ length = 0;
+ capacity *= 2;
+ if (capacity > (1 << 24))
+ break;
+ str = g_new (gunichar2, capacity);
+ if (!str)
+ break;
+ length = GetModuleFileNameW ((HMODULE)mod, (PWSTR)str, capacity);
+ success = length && length < (capacity - 1); // This function does not truncate, but - 1 anyway.
+ if (success)
+ break;
+ g_free (str); // error or too small
+ str = NULL;
+ if (!length) // error
+ break;
+ }
+ *pstr = str;
+ *plength = length;
+ return success;
+}
+
+// This is not about GModule but is still a close fit.
+// This is not named "g_" but that should be ok.
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_module_filename_ex (gpointer process, gpointer mod, gunichar2** pstr, guint32* plength)
+{
+ gunichar2* str = NULL;
+ guint32 capacity = 32; // tunable
+ guint32 length = 0;
+ gboolean success = FALSE;
+
+ while (TRUE)
+ {
+ length = 0;
+ capacity *= 2;
+ if (capacity > (1 << 24))
+ break;
+ str = g_new (gunichar2, capacity);
+ if (!str)
+ break;
+ length = GetModuleFileNameExW (process, (HMODULE)mod, str, capacity);
+ success = length && length < (capacity - 1); // This function truncates, thus the - 1.
+ if (success)
+ break;
+ g_free (str); // error or too small
+ str = NULL;
+ if (!length) // error
+ break;
+ }
+ *pstr = str;
+ *plength = length;
+ return success;
+}
+
+gboolean
+mono_get_module_basename (gpointer process, gpointer mod, gunichar2** pstr, guint32* plength)
+{
+ gunichar2* str = NULL;
+ guint32 capacity = 32; // tunable
+ guint32 length = 0;
+ gboolean success = FALSE;
+
+ while (TRUE)
+ {
+ length = 0;
+ capacity *= 2;
+ if (capacity > (1 << 24))
+ break;
+ str = g_new (gunichar2, capacity);
+ if (!str)
+ break;
+ length = GetModuleBaseNameW (process, (HMODULE)mod, str, capacity);
+ success = length && length < (capacity - 1); // This function truncates, thus the - 1.
+ if (success)
+ break;
+ g_free (str); // error or too small
+ str = NULL;
+ if (!length) // error
+ break;
+ }
+ *pstr = str;
+ *plength = length;
+ return success;
+}
+
+// g_free the result
+// No MAX_PATH limit.
+gboolean
+mono_get_current_directory (gunichar2** pstr, guint32* plength)
+{
+ gunichar2* str = NULL;
+ guint32 capacity = 32; // tunable
+ guint32 length = 0;
+ gboolean success = FALSE;
+
+ while (TRUE)
+ {
+ length = 0;
+ capacity *= 2;
+ if (capacity > (1 << 24))
+ break;
+ str = g_new (gunichar2, capacity);
+ if (!str)
+ break;
+ // Call in loop, not just twice, in case another thread is changing it.
+ // Result is transient in currentness and validity (can get deleted or become a file).
+ length = GetCurrentDirectoryW (capacity, (PWSTR)str);
+ success = length && length < (capacity - 1);
+ if (success)
+ break;
+ g_free (str); // error or too small
+ str = NULL;
+ if (!length) // error
+ break;
+ }
+ *pstr = str;
+ *plength = length;
+ return success;
+}
#define EXTERNAL_SYMBOL "system"
#endif
+#if _WIN32
+#include <windows.h>
+#include <wchar.h>
+#include <psapi.h>
+#endif
+
void G_MODULE_EXPORT
dummy_test_export (void);
return OK;
}
+static RESULT
+test_module_get_module_filename (void)
+{
+#if _WIN32
+ const HMODULE mods [ ] = {NULL, LoadLibraryW (L"msvcrt.dll"), (HMODULE)(gssize)-1 };
+
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j <= 2; ++j) {
+ const HMODULE mod = mods [i];
+ wchar_t* str = { 0 };
+ guint32 length = { 0 };
+ wchar_t buf2 [999] = { 0 };
+ wchar_t buf3 [2] = { 0 };
+ gboolean success = { 0 };
+ guint32 length2 = { 0 };
+ gboolean success2 = { 0 };
+ guint32 length3 = { 0 };
+ gboolean success3 = { 0 };
+
+ switch (j) {
+ case 0:
+ success = mono_get_module_filename (mod, &str, &length);
+ length2 = GetModuleFileNameW (mod, buf2, G_N_ELEMENTS (buf2)); // large buf
+ length3 = GetModuleFileNameW (mod, buf3, 1); // small buf
+ break;
+ case 1:
+ success = mono_get_module_filename_ex (GetCurrentProcess (), mods [i], &str, &length);
+ length2 = GetModuleFileNameExW (GetCurrentProcess (), mod, buf2, G_N_ELEMENTS (buf2)); // large buf
+ length3 = GetModuleFileNameExW (GetCurrentProcess (), mod, buf3, 1); // small buf
+ break;
+ case 2:
+ success = mono_get_module_basename (GetCurrentProcess (), mod, &str, &length);
+ length2 = GetModuleBaseNameW (GetCurrentProcess (), mod, buf2, G_N_ELEMENTS (buf2)); // large buf
+ length3 = GetModuleBaseNameW (GetCurrentProcess (), mod, buf3, 1); // small buf
+ break;
+ }
+ success2 = length2 && length2 < G_N_ELEMENTS (buf2);
+ success3 = length3 == 1;
+ printf ("j:%d s:%X s2:%X s3:%X l:%u l2:%u l3:%u str:%X b2:%X b3:%X\n",
+ j,
+ success, success2, success3,
+ length, length2, length3,
+ str ? str [0] : 0, buf2 [0], buf3 [0]);
+ g_assert (success == success2);
+ g_assert (success == success3 || j > 0);
+ g_assert (!success || str [0] == buf2 [0]);
+ //g_assert (!success || str [0] == buf3 [0]);
+ g_assert (length3 == 0 || length3 == 1);
+ g_assert (length == (success2 ? wcslen (buf2) :0));
+ g_assert (!success || !wcscmp (str, buf2));
+ g_assert (!success || str);
+ if (success)
+ printf ("%p %ls %ls %d %d\n", mod, str, buf2, length, length2);
+ else
+ printf ("!%p %u\n", str, (guint)length);
+ g_free (str);
+ }
+ }
+#endif
+ return OK;
+}
+
+static RESULT
+test_get_current_directory (void)
+{
+#if _WIN32
+ wchar_t* str = { 0 };
+ guint32 length = { 0 };
+ gboolean success = mono_get_current_directory (&str, &length);
+ wchar_t buf2 [999] = { 0 };
+ const int length2 = GetCurrentDirectoryW (G_N_ELEMENTS (buf2), buf2);
+ const gboolean success2 = length2 && length2 < G_N_ELEMENTS (buf2);
+ wchar_t buf3 [2] = { 0 };
+ const int length3 = GetCurrentDirectoryW (G_N_ELEMENTS (buf3), buf3);
+ const gboolean success3 = length3 > 0;
+ printf ("s:%X s2:%X s3:%X str:%X b2:%X b3:%X\n", success, success2, success3, str ? str [0] : 0, buf2 [0], buf3 [0]);
+ g_assert (length == length2);
+ g_assert (success == success2);
+ g_assert (success == success3);
+ g_assert (!success || !wcscmp (str, buf2));
+ g_assert (!success || str);
+ if (success)
+ printf ("%ls\n%ls\n", str, buf2);
+ else
+ printf ("!%p %u\n", str, (guint)length);
+ g_free (str);
+#endif
+ return OK;
+}
+
static Test module_tests [] = {
{"g_module_symbol_null", test_module_symbol_null},
+ {"module_get_module_filename", test_module_get_module_filename},
+ {"get_current_directory", test_get_current_directory},
{NULL, NULL}
};
MonoStringHandle
ves_icall_System_Diagnostics_Process_ProcessName_internal (HANDLE process, MonoError *error)
{
- gunichar2 name [MAX_PATH]; // FIXME MAX_PATH
- const guint32 len = GetModuleFileNameW (NULL, name, G_N_ELEMENTS (name));
- if (len == 0)
+ gunichar2* name = NULL;
+ guint32 len = 0;
+ // FIXME give allocator to mono_get_module_file_name to avoid copies, here and many other
+ if (!mono_get_module_file_name (NULL, &name, &len))
return NULL_HANDLE_STRING;
- return mono_string_new_utf16_handle (mono_domain_get (), name, len, error);
+ MonoStringHandle res = mono_string_new_utf16_handle (mono_domain_get (), name, len, error);
+ g_free (name);
+ return res;
}
MonoBoolean
int
main (void)
{
- TCHAR szFileName[MAX_PATH];
+ gunichar2* module_file_name;
+ guint32 length;
int argc;
gunichar2** argvw;
gchar** argv;
int i;
- DWORD count;
-
- argvw = CommandLineToArgvW (GetCommandLine (), &argc);
+
+ argvw = CommandLineToArgvW (GetCommandLineW (), &argc);
argv = g_new0 (gchar*, argc + 1);
for (i = 0; i < argc; i++)
argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
LocalFree (argvw);
- if ((count = GetModuleFileName (NULL, szFileName, MAX_PATH)) != 0){
- char *entry = g_utf16_to_utf8 (szFileName, count, NULL, NULL, NULL);
+ if (mono_get_module_file_nae (NULL, &szFileName, NULL))
+
+ if ((mono_get_module_filename (NULL, &module_file_name, &length))) {
+ char *entry = g_utf16_to_utf8 (module_file_name, length, NULL, NULL, NULL);
+ g_free (module_file_name);
probe_embedded (entry, &argc, &argv);
}