Paul Chitescu schrieb:
On Tue, 29 Apr 2008, Peter Beutner wrote:
Steven Edwards schrieb:
On Mon, Apr 28, 2008 at 3:51 AM, Steven Edwards <[EMAIL PROTECTED]> wrote:
On Sun, Apr 27, 2008 at 9:19 AM, Dan Kegel <[EMAIL PROTECTED]> wrote:
>  2. You never clear that environment variable... what happens
>  when an app just tests for the existence of a DLL by
>  trying to load it?  We don't want to print an error then.
>  (That's why I originally suggested clearing the env var
>  after the app finished loading.  That's still broken -- it
>  won't catch errors in helper exes -- but it's better than nothing.)

 I assume you mean if the application is just checking manually for the
 dll via GetModuleHandle or LoadLibrary? I'll write a test case for
 this to see if it causes a problem. My assumption was that the failure
 case for that was at a higher level but I'll check with a test case. I
 don't think we need to clear the variable....what I mean is I wonder
 if there is a way to set the variable to be inherited by all child
 processes launched by start.exe.so in unix mode. I'll look in to this
 as well.

I assumed the code path must be different so I wrote a test app that
tried to do a GetProcAddress or LoadLibrary on a non-existent dll and
was right, It did not throw the messagebox.

But I think it will still trigger the msg box if the application is checking for an existent foo.dll via LoadLibrary and foo.dll depends on a missing xyz.dll.
It won't trigger if you clear the environment variable as Dan said.
I'm not sure though which way is the right one here.

Windows doesn't do that - when my application tries to load a module that links against a missing DLL then LoadLibrary simply fails without showing any message. The "ignore it if LoadLibrary fails" logic is common in many programs that use optional plugins.

So clearing the env variable would be the correct thing. But still not entirely
satisfying as mentioned above by Dan.

I just tried to solve it differently, doing it entirely in ntdll.
(and probably you could even do it without using a global variable)
It certainly avoids all that pain dealing with environment variables ;).

Not really heavily tested, but I think it works.


diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 3b60d60..6e814ff 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <stdarg.h>
+#include <stdio.h>
 #ifdef HAVE_SYS_MMAN_H
 # include <sys/mman.h>
 #endif
@@ -99,6 +100,7 @@ struct builtin_load_info
 static struct builtin_load_info default_load_info;
 static struct builtin_load_info *builtin_load_info = &default_load_info;
 
+static int report_missing_dll_verbose;      /* display msgbox if importing a dll fails */
 static HANDLE main_exe_file;
 static UINT tls_module_count;      /* number of modules with TLS directory */
 static UINT tls_total_size;        /* total size of TLS storage */
@@ -467,6 +469,46 @@ static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *
 
 }
 
+static FARPROC get_msgbox_func(void)
+{
+    WCHAR user32[] = {'u','s','e','r','3','2','.','d','l','l',0};
+    NTSTATUS status;
+    HMODULE hdll;
+    ANSI_STRING str;
+    UNICODE_STRING wstr;
+    FARPROC pMessageBoxA;
+
+    RtlInitUnicodeString( &wstr, user32 );
+    status = LdrLoadDll(0, 0, &wstr, &hdll);
+    if (status != STATUS_SUCCESS)
+        return NULL;
+
+    RtlInitAnsiString( &str, "MessageBoxA" );
+    status = LdrGetProcedureAddress( hdll, &str, 0, (void**)&pMessageBoxA );
+    if (status != STATUS_SUCCESS)
+        return NULL;
+
+    return pMessageBoxA;
+}
+
+/* don't want to include winuser.h */
+#define MB_ICONERROR     0x00000010
+static void report_missing_dll(const char *dll, WCHAR* imported_by)
+{
+    FARPROC pMessageBoxA;
+    char msg[MAX_PATH];
+
+    pMessageBoxA = get_msgbox_func();
+    if(report_missing_dll_verbose && pMessageBoxA) {
+        snprintf(msg, MAX_PATH, "Library %s (which is needed by %s) not found\n",
+                dll,  debugstr_w(imported_by));
+        pMessageBoxA(NULL, msg, "Error: Failed to start application", MB_ICONERROR);
+    }
+
+    ERR("Library %s (which is needed by %s) not found\n",
+        dll, debugstr_w(imported_by));
+}
+
 
 /*************************************************************************
  *		import_dll
@@ -517,8 +559,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
     if (status)
     {
         if (status == STATUS_DLL_NOT_FOUND)
-            ERR("Library %s (which is needed by %s) not found\n",
-                name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
+            report_missing_dll(name, current_modref->ldr.FullDllName.Buffer);
         else
             ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
                 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
@@ -2414,7 +2455,9 @@ void WINAPI LdrInitializeThunk( ULONG unknown1, ULONG unknown2, ULONG unknown3,
 
     actctx_init();
     load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
+    report_missing_dll_verbose = 1;
     if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
+    report_missing_dll_verbose = 0;
     if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
     if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
 



Reply via email to