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

Dmitry Timoshkov dmitry at codeweavers.com
Tue Dec 25 23:26:40 CST 2007


Hello,

previously I didn't test the patch with sysupe.exe (the problematic installer
mentioned in the bug 3620) because the link to it was removed from the original
site due to deprecated support for Win9x. This version of the patch has been
tested with sysupe.exe found on the original site with a link found by google
(sysupe.exe is still there but all the links to it are removed).

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     |   89 ++++++++++++++++++++++++++++++++++++++++++
 dlls/kernel32/ne_module.c    |   22 ++++++++--
 dlls/kernel32/winoldap.spec  |    2 +
 programs/winecfg/libraries.c |    1 +
 7 files changed, 115 insertions(+), 6 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..555eaca 100644
--- a/dlls/kernel32/kernel16.c
+++ b/dlls/kernel32/kernel16.c
@@ -130,3 +130,92 @@ 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 app_name;
+    LPSTR  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;
+    HINSTANCE16 hwinoldap;
+
+    args->ret = FALSE;
+
+    memset( &startup, 0, sizeof(startup) );
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = args->cmd_show;
+
+    if (CreateProcessA( args->app_name, args->cmd_line, NULL, NULL, FALSE,
+                        0, NULL, NULL, &startup, &info ))
+    {
+        /* 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.dll" );
+    FreeLibrary16( hwinoldap );
+
+    if (!args->ret)
+        SetEvent( args->event );
+
+    return 0;
+}
+
+/**************************************************************************
+ *           WinExec   (WINOLDAP.1)
+ */
+BOOL WINAPI WINOLDAP_WinExec( LPCSTR app_name, LPSTR cmd_line, UINT cmd_show )
+{
+    HANDLE hthread;
+    struct winexec_thread_args args;
+
+    args.event = CreateEventW( NULL, 0, 0, NULL );
+    args.app_name = app_name;
+    args.cmd_line = cmd_line;
+    args.cmd_show = cmd_show;
+    args.ret = FALSE;
+
+    hthread = CreateThread( NULL, 0, winexec_thread, &args, 0, 0 );
+    if (hthread)
+    {
+        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..e25d757 100644
--- a/dlls/kernel32/ne_module.c
+++ b/dlls/kernel32/ne_module.c
@@ -1701,16 +1701,30 @@ HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
     }
     else ret = GetLastError();
 
-    HeapFree( GetProcessHeap(), 0, cmdline );
-    if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
-
     if (ret == 21 || ret == ERROR_BAD_FORMAT)  /* 32-bit module or unknown executable*/
     {
         DWORD count;
         ReleaseThunkLock( &count );
-        ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) );
+
+        ret = LoadModule16( "winoldap.dll", NULL );
+
+        if (ret >= 32)
+        {
+            BOOL (WINAPI *pWinExec)(LPCSTR, LPSTR, UINT);
+            FARPROC16 proc;
+
+            proc = GetProcAddress16( ret, "WinExec" );
+            /* WINOLDAP is always a builtin dll */
+            pWinExec = (void *)((ENTRYPOINT16 *)MapSL( (SEGPTR)proc ))->target;
+            if (!pWinExec( buffer, cmdline + 1, nCmdShow ))
+                ret = 21;
+        }
         RestoreThunkLock( count );
     }
+
+    HeapFree( GetProcessHeap(), 0, cmdline );
+    if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
+
     return ret;
 }
 
diff --git a/dlls/kernel32/winoldap.spec b/dlls/kernel32/winoldap.spec
new file mode 100644
index 0000000..50d8ea3
--- /dev/null
+++ b/dlls/kernel32/winoldap.spec
@@ -0,0 +1,2 @@
+# Wine extension
+1 pascal WinExec(str 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