2009-03-02 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / process.c
index 599af5bf03113d171b16797026427f1c46c8d477..cfdce2ca9943919055ba80fd28ef14e461c1e0e0 100644 (file)
@@ -4,8 +4,8 @@
  * Author:
  *     Dick Porter (dick@ximian.com)
  *
- * (C) 2002 Ximian, Inc.
- * Copyright (c) 2002-2006 Novell, Inc.
+ * Copyright 2002 Ximian, Inc.
+ * Copyright 2002-2006 Novell, Inc.
  */
 
 #include <config.h>
@@ -21,6 +21,7 @@
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/exception.h>
 #include <mono/utils/strenc.h>
+#include <mono/utils/mono-proclib.h>
 #include <mono/io-layer/io-layer.h>
 /* FIXME: fix this code to not depend so much on the inetrnals */
 #include <mono/metadata/class-internals.h>
@@ -176,6 +177,7 @@ static void process_set_field_bool (MonoObject *obj, const gchar *fieldname,
 #define SFI_PRODUCTNAME                "\\StringFileInfo\\%02X%02X%02X%02X\\ProductName"
 #define SFI_PRODUCTVERSION     "\\StringFileInfo\\%02X%02X%02X%02X\\ProductVersion"
 #define SFI_SPECIALBUILD       "\\StringFileInfo\\%02X%02X%02X%02X\\SpecialBuild"
+#define EMPTY_STRING           (gunichar2*)"\000\000"
 
 static void process_module_string_read (MonoObject *filever, gpointer data,
                                        const gchar *fieldname,
@@ -194,12 +196,15 @@ static void process_module_string_read (MonoObject *filever, gpointer data,
 
        lang_key = g_utf8_to_utf16 (lang_key_utf8, -1, NULL, NULL, NULL);
 
-       if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars)) {
+       if (VerQueryValue (data, lang_key, (gpointer *)&buffer, &chars) && chars > 0) {
 #ifdef DEBUG
-               g_message ("%s: found %d bytes of [%s]", __func__, bytes,
-                          g_utf16_to_utf8 (buffer, bytes, NULL, NULL, NULL));
+               g_message ("%s: found %d chars of [%s]", __func__, chars,
+                          g_utf16_to_utf8 (buffer, chars, NULL, NULL, NULL));
 #endif
-               process_set_field_string (filever, fieldname, buffer, chars);
+               /* chars includes trailing null */
+               process_set_field_string (filever, fieldname, buffer, chars - 1);
+       } else {
+               process_set_field_string (filever, fieldname, EMPTY_STRING, 0);
        }
 
        g_free (lang_key);
@@ -245,7 +250,8 @@ static void process_get_fileversion (MonoObject *filever, gunichar2 *filename)
        gunichar2 *query;
        UINT ffi_size, trans_size;
        BOOL ok;
-       int i;
+       gunichar2 lang_buf[128];
+       guint32 lang, lang_count;
 
        datalen = GetFileVersionInfoSize (filename, &verinfohandle);
        if (datalen) {
@@ -292,42 +298,77 @@ static void process_get_fileversion (MonoObject *filever, gunichar2 *filename)
                        if (VerQueryValue (data, query,
                                           (gpointer *)&trans_data,
                                           &trans_size)) {
-                               /* Look for neutral or en_US language data
-                                * (or should we use the first language ID we
-                                * see?)
+                               /* use the first language ID we see
                                 */
-                               for (i = 0; i < trans_size; i += 4) {
+                               if (trans_size >= 4) {
 #ifdef DEBUG
-                                       g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), trans_data[i], trans_data[i+1], trans_data[i+2], trans_data[i+3]);
+                                       g_message("%s: %s has 0x%0x 0x%0x 0x%0x 0x%0x", __func__, g_utf16_to_utf8 (filename, -1, NULL, NULL, NULL), trans_data[0], trans_data[1], trans_data[2], trans_data[3]);
 #endif
-
-                                       if ((trans_data[i] == 0x09 &&
-                                            trans_data[i+1] == 0x04 &&
-                                            trans_data[i+2] == 0xb0 &&
-                                            trans_data[i+3] == 0x04) ||
-                                           (trans_data[i] == 0x00 &&
-                                            trans_data[i+1] == 0x00 &&
-                                            trans_data[i+2] == 0xb0 &&
-                                            trans_data[i+3] == 0x04) ||
-                                           (trans_data[i] == 0x7f &&
-                                            trans_data[i+1] == 0x00 &&
-                                            trans_data[i+2] == 0xb0 &&
-                                            trans_data[i+3] == 0x04)) {
-                                               gunichar2 lang_buf[128];
-                                               guint32 lang, lang_count;
-
-                                               lang = (trans_data[i]) |
-                                                      (trans_data[i+1] << 8) |
-                                                      (trans_data[i+2] << 16) |
-                                                      (trans_data[i+3] << 24);
-                                               lang_count = VerLanguageName (lang, lang_buf, 128);
-                                               if (lang_count) {
-                                                       process_set_field_string (filever, "language", lang_buf, lang_count);
-                                               }
-                                               process_module_stringtable (filever, data, trans_data[i], trans_data[i+1]);
+                                       lang = (trans_data[0]) |
+                                               (trans_data[1] << 8) |
+                                               (trans_data[2] << 16) |
+                                               (trans_data[3] << 24);
+                                       /* Only give the lower 16 bits
+                                        * to VerLanguageName, as
+                                        * Windows gets confused
+                                        * otherwise
+                                        */
+                                       lang_count = VerLanguageName (lang & 0xFFFF, lang_buf, 128);
+                                       if (lang_count) {
+                                               process_set_field_string (filever, "language", lang_buf, lang_count);
                                        }
+                                       process_module_stringtable (filever, data, trans_data[0], trans_data[1]);
+                               }
+                       } else {
+                               /* No strings, so set every field to
+                                * the empty string
+                                */
+                               process_set_field_string (filever,
+                                                         "comments",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "companyname",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "filedescription",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "fileversion",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "internalname",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "legalcopyright",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "legaltrademarks",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "originalfilename",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "privatebuild",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "productname",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "productversion",
+                                                         EMPTY_STRING, 0);
+                               process_set_field_string (filever,
+                                                         "specialbuild",
+                                                         EMPTY_STRING, 0);
+
+                               /* And language seems to be set to
+                                * en_US according to bug 374600
+                                */
+                               lang_count = VerLanguageName (0x0409, lang_buf, 128);
+                               if (lang_count) {
+                                       process_set_field_string (filever, "language", lang_buf, lang_count);
                                }
                        }
+                       
                        g_free (query);
                }
                g_free (data);
@@ -454,32 +495,46 @@ quote_path (const gchar *path)
 static gboolean
 complete_path (const gunichar2 *appname, gchar **completed)
 {
-       gchar *utf8app;
+       gchar *utf8app, *utf8appmemory;
        gchar *found;
 
-       utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
+       utf8appmemory = utf8app = g_utf16_to_utf8 (appname, -1, NULL, NULL, NULL);
+#ifdef PLATFORM_WIN32 // Should this happen on all platforms? 
+       {
+               // remove the quotes around utf8app.
+               size_t len;
+               len = strlen (utf8app);
+               if (len) {
+                       if (utf8app[len-1] == '\"')
+                               utf8app[len-1] = '\0';
+                       if (utf8app[0] == '\"')
+                               utf8app++;
+               }
+       }
+#endif
+
        if (g_path_is_absolute (utf8app)) {
                *completed = quote_path (utf8app);
-               g_free (utf8app);
+               g_free (utf8appmemory);
                return TRUE;
        }
 
        if (g_file_test (utf8app, G_FILE_TEST_IS_EXECUTABLE) && !g_file_test (utf8app, G_FILE_TEST_IS_DIR)) {
                *completed = quote_path (utf8app);
-               g_free (utf8app);
+               g_free (utf8appmemory);
                return TRUE;
        }
        
        found = g_find_program_in_path (utf8app);
        if (found == NULL) {
                *completed = NULL;
-               g_free (utf8app);
+               g_free (utf8appmemory);
                return FALSE;
        }
 
        *completed = quote_path (found);
        g_free (found);
-       g_free (utf8app);
+       g_free (utf8appmemory);
        return TRUE;
 }
 
@@ -753,6 +808,22 @@ MonoBoolean ves_icall_System_Diagnostics_Process_WaitForExit_internal (MonoObjec
        }
 }
 
+MonoBoolean ves_icall_System_Diagnostics_Process_WaitForInputIdle_internal (MonoObject *this, HANDLE process, gint32 ms)
+{
+       guint32 ret;
+       
+       MONO_ARCH_SAVE_REGS;
+
+       if(ms<0) {
+               /* Wait forever */
+               ret=WaitForInputIdle (process, INFINITE);
+       } else {
+               ret=WaitForInputIdle (process, ms);
+       }
+
+       return (ret) ? FALSE : TRUE;
+}
+
 gint64 ves_icall_System_Diagnostics_Process_ExitTime_internal (HANDLE process)
 {
        gboolean ret;
@@ -945,3 +1016,45 @@ ves_icall_System_Diagnostics_Process_SetPriorityClass (HANDLE process, gint32 pr
        *error = ret == 0 ? GetLastError () : 0;
        return ret;
 }
+
+HANDLE
+ves_icall_System_Diagnostics_Process_ProcessHandle_duplicate (HANDLE process)
+{
+       HANDLE ret;
+
+       MONO_ARCH_SAVE_REGS;
+
+#ifdef DEBUG
+       g_message ("%s: Duplicating process handle %p", __func__, process);
+#endif
+       
+       DuplicateHandle (GetCurrentProcess (), process, GetCurrentProcess (),
+                        &ret, THREAD_ALL_ACCESS, TRUE, 0);
+       
+       return ret;
+}
+
+void
+ves_icall_System_Diagnostics_Process_ProcessHandle_close (HANDLE process)
+{
+       MONO_ARCH_SAVE_REGS;
+
+#ifdef DEBUG
+       g_message ("%s: Closing process handle %p", __func__, process);
+#endif
+
+       CloseHandle (process);
+}
+
+gint64
+ves_icall_System_Diagnostics_Process_GetProcessData (int pid, gint32 data_type, gint32 *error)
+{
+       MonoProcessError perror;
+       guint64 res;
+
+       res = mono_process_get_data_with_error (GINT_TO_POINTER (pid), data_type, &perror);
+       if (error)
+               *error = perror;
+       return res;
+}
+