kernel32: Add an ability to execute 32-bit applications from 16-bit ones using winoldap.dll

Dmitry Timoshkov dmitry at codeweavers.com
Tue Dec 25 00:24:46 CST 2007


Hello,

this patch should fix the problem reported in the bug 3620.

winoldap.mod in Windows is a 16-bit .exe which uses its command line to load
a 32-bit module and pass the parameters to it. Since winebuild doesn't allow
to create a 16-bit builtin exe, I decided to create a 16-bit builtin dll
instead. That adds some complexity due to need to create another thread to
launch a 32-bit application from, and wait until it finishes.

Changelog:
    kernel32: Add an ability to execute 32-bit applications from 16-bit
    ones using winoldap.dll.
---
 .gitignore                   |    1 +
 dlls/Makefile.in             |    3 +-
 dlls/kernel32/Makefile.in    |    3 +-
 dlls/kernel32/kernel16.c     |  103 ++++++++++++++++++++++++++++++++++++++++++
 dlls/kernel32/ne_module.c    |   19 +++++++-
 dlls/kernel32/winoldap.spec  |    2 +
 programs/winecfg/libraries.c |    1 +
 7 files changed, 129 insertions(+), 3 deletions(-)
 create mode 100644 dlls/kernel32/winoldap.spec

diff --git a/.gitignore b/.gitignore
index eee1787..5767c9c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -543,6 +543,7 @@ dlls/winmm/tests/winmm_crosstest.exe
 dlls/winmm/winmm_res.res
 dlls/winnls.dll16
 dlls/winnls32/libwinnls32.def
+dlls/winoldap.dll16
 dlls/winscard/libwinscard.def
 dlls/winscard/rsrc.res
 dlls/winsock.dll16
diff --git a/dlls/Makefile.in b/dlls/Makefile.in
index d7b0976..1ff64b7 100644
--- a/dlls/Makefile.in
+++ b/dlls/Makefile.in
@@ -385,6 +385,7 @@ WIN16_FILES = \
 	wineps16.drv16 \
 	wing.dll16 \
 	winnls.dll16 \
+	winoldap.dll16 \
 	winsock.dll16 \
 	wintab.dll16 \
 	wprocs.dll16
@@ -412,7 +413,7 @@ dispdib.dll16 gdi.exe16 wing.dll16:
 imm.dll16:
 	echo "imm32.dll" >$@
 
-comm.drv16 krnl386.exe16 stress.dll16 system.drv16 toolhelp.dll16 win87em.dll16 windebug.dll16:
+comm.drv16 krnl386.exe16 stress.dll16 system.drv16 toolhelp.dll16 win87em.dll16 windebug.dll16 winoldap.dll16:
 	echo "kernel32.dll" >$@
 
 lzexpand.dll16:
diff --git a/dlls/kernel32/Makefile.in b/dlls/kernel32/Makefile.in
index aab68e6..01c5847 100644
--- a/dlls/kernel32/Makefile.in
+++ b/dlls/kernel32/Makefile.in
@@ -16,7 +16,8 @@ SPEC_SRCS16 = \
 	system.drv.spec \
 	toolhelp.spec \
 	win87em.spec \
-	windebug.spec
+	windebug.spec \
+	winoldap.spec
 
 C_SRCS = \
 	actctx.c \
diff --git a/dlls/kernel32/kernel16.c b/dlls/kernel32/kernel16.c
index 50b11a0..bc9888b 100644
--- a/dlls/kernel32/kernel16.c
+++ b/dlls/kernel32/kernel16.c
@@ -130,3 +130,106 @@ HANDLE WINAPI CreateThread16( SECURITY_ATTRIBUTES *sa, DWORD stack,
     args->param = param;
     return CreateThread( sa, stack, start_thread16, args, flags, id );
 }
+
+/***********************************************************************
+ *           wait_input_idle
+ *
+ * Wrapper to call WaitForInputIdle user32 API
+ */
+static DWORD wait_input_idle( HANDLE process, DWORD timeout )
+{
+    HMODULE user32 = GetModuleHandleA( "user32.dll" );
+    if (user32)
+    {
+        DWORD (WINAPI *pWaitForInputIdle)( HANDLE hProcess, DWORD dwTimeOut );
+
+        pWaitForInputIdle = (void *)GetProcAddress( user32, "WaitForInputIdle" );
+        return pWaitForInputIdle( process, timeout );
+    }
+    return 0;
+}
+
+struct winexec_thread_args
+{
+    HANDLE event;
+    LPCSTR cmd_line;
+    UINT   cmd_show;
+    BOOL   ret;
+};
+
+static DWORD WINAPI winexec_thread( LPVOID param )
+{
+    struct winexec_thread_args *args = (struct winexec_thread_args *)param;
+    PROCESS_INFORMATION info;
+    STARTUPINFOA startup;
+    char *cmdline;
+    DWORD count;
+
+    args->ret = FALSE;
+
+    memset( &startup, 0, sizeof(startup) );
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = args->cmd_show;
+
+    /* cmdline needs to be writable for CreateProcess */
+    if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(args->cmd_line)+1 )))
+    {
+        SetEvent( args->event );
+        return 0;
+    }
+    strcpy( cmdline, args->cmd_line );
+
+    ReleaseThunkLock( &count );
+
+    if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
+                        0, NULL, NULL, &startup, &info ))
+    {
+        HINSTANCE16 hwinoldap;
+
+        /* Give 30 seconds to the app to come up */
+        wait_input_idle( info.hProcess, 30000 );
+
+        args->ret = TRUE;
+        SetEvent(args->event);
+
+        WaitForSingleObject( info.hProcess, INFINITE );
+
+        CloseHandle( info.hThread );
+        CloseHandle( info.hProcess );
+
+        /* decrement WINOLDAP usage count to signal that we have finished */
+        hwinoldap = GetModuleHandle16( "winoldap" );
+        FreeLibrary16( hwinoldap );
+    }
+
+    RestoreThunkLock( count );
+    HeapFree( GetProcessHeap(), 0, cmdline );
+
+    if (!args->ret);
+        SetEvent( args->event );
+
+    return 0;
+}
+
+/**************************************************************************
+ *           WinExec   (WINOLDAP.1)
+ */
+BOOL WINAPI WINOLDAP_WinExec( LPCSTR cmd_line, UINT cmd_show )
+{
+    HANDLE hthread;
+    struct winexec_thread_args args;
+
+    args.event = CreateEventW( NULL, 0, 0, NULL );
+    args.cmd_line = cmd_line;
+    args.cmd_show = cmd_show;
+    args.ret = FALSE;
+
+    hthread = CreateThread( NULL, 0, winexec_thread, &args, 0, 0 );
+    if (!hthread) return FALSE;
+
+    WaitForSingleObject( args.event, INFINITE );
+    CloseHandle( args.event );
+
+    return args.ret;
+}
diff --git a/dlls/kernel32/ne_module.c b/dlls/kernel32/ne_module.c
index e41ced9..2d95e41 100644
--- a/dlls/kernel32/ne_module.c
+++ b/dlls/kernel32/ne_module.c
@@ -1704,7 +1704,24 @@ HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
     HeapFree( GetProcessHeap(), 0, cmdline );
     if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
 
-    if (ret == 21 || ret == ERROR_BAD_FORMAT)  /* 32-bit module or unknown executable*/
+    if (ret == 21) /* 32-bit module */
+    {
+        ret = LoadModule16( "winoldap.dll", NULL );
+
+        if (ret >= 32)
+        {
+            BOOL (WINAPI *pWinExec)(LPCSTR, UINT);
+            FARPROC16 proc;
+
+            proc = GetProcAddress16( ret, "WinExec" );
+            /* WINOLDAP is always a builtin dll */
+            pWinExec = (void *)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
+            pWinExec( lpCmdLine, nCmdShow );
+        }
+        else
+            ret = 21;
+    }
+    else if (ret == ERROR_BAD_FORMAT) /* unknown executable */
     {
         DWORD count;
         ReleaseThunkLock( &count );
diff --git a/dlls/kernel32/winoldap.spec b/dlls/kernel32/winoldap.spec
new file mode 100644
index 0000000..29dc85e
--- /dev/null
+++ b/dlls/kernel32/winoldap.spec
@@ -0,0 +1,2 @@
+# Wine extension
+1 pascal WinExec(str long) WINOLDAP_WinExec
diff --git a/programs/winecfg/libraries.c b/programs/winecfg/libraries.c
index 8e4e46b..2a168be 100644
--- a/programs/winecfg/libraries.c
+++ b/programs/winecfg/libraries.c
@@ -81,6 +81,7 @@ static const char * const builtin_only[] =
     "wineps.drv",
     "winex11.drv",
     "winmm",
+    "winoldap",
     "wintab32",
     "wnaspi32",
     "wow32",
-- 
1.5.3.7






More information about the wine-patches mailing list