Release 950817

Thu Aug 17 19:30:14 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [*/Makefile.in]
	Removed winelibclean target, as it doesn't work anyway.

	* [controls/button.c]
	Avoid drawing the focus rectangle outside of the button.

	* [controls/widgets.c]
	Fixed bug with the size of the reserved bytes for the Edit
	control (caused Eudora to crash).

	* [debugger/*] [include/debugger.h]
	Unified debugger address handling. Segmented and linear addresses
	are no grouped in a single type DBG_ADDR.
	All commands now accept seg:off addresses.
	Module entry points are now loaded upon first entry to the
	debugger, so that entry points of the loaded executable also
	appear in the symbol table.

	* [include/registers.h] [miscemu/*.c]
	Register macros are now of the form 'AX_reg(context)' instead of 'AX'.
	This makes code less readable, but will prevent a lot of name
	clashes with other definitions. It also avoids a hidden reference
	to the 'context' variable.

	* [ipc/dde_atom.c] [misc/atom.c]
	All *AddAtom and *FindAtom functions now take a SEGPTR parameter,
	to allow supporting integer atoms.
	Moved atom.c to memory/ directory.

	* [loader/task.c]
	Fixed environment allocation to compute the size dynamically.
	Added 'windir' environment variable.
	Fixed GetDOSEnvironment() to return the current task environment.

	* [windows/message.c]
	Fixed bug in MSG_GetWindowForEvent().

Wed Aug  9 11:40:43 1995  Marcus Meissner  <msmeissn@faui01.informatik.uni-erlangen.de>

	* [include/ole.h]
	Added a lot of structures  from my Borland Manual. Neither complete,
	nor 100% right (check please)
	
	* [misc/shell.c]
	Fixed some of the Reg* functions.
	Enhanced ShellExecute.
	Please test: wine "regedit.exe /v" mplayer.exe soundrec.exe
	Do YOU know the format of \WINDOWS\REG.DAT? Mail me please :)

	* [misc/dos_fs.c]
	Make umsdos mounted windows dirs work again.

	* [miscemu/emulate.c]
	Added some comments, preimplementation of subfunction 7.

	* [multimedia/mmsystem.c]
	Implemented mciSendString. not complete, not clean, not
	necessarily working (only checked with a program which uses
 	'cdaudio' (one working program is cool.exe, a shareware waveditor
 	with cdaudio play facilities.)

	* [multimedia/mcicda.c]
	Segptr fixes in DriverProc
	Default cdrom drive in Linux is /dev/cdrom ... usually a symbolic
 	link to your real cdrom device.

Tue Aug  8 19:41:50 CDT 1995 Daniel Schepler <dks2@cec.wustl.edu>

	* [loader/resource.c]
	Don't crash in a LoadString to NULL

	* [loader/resource.c]
	Fixed accelerators to work with modifiers.  (ALT-x modifiers still
 	won't work unless the ALT keypress exited the menu.)

	* [misc/file.c]
	Expand a file to the current offset with an _lwrite of size zero.

	* [misc/file.c]
	Set a newly created file to read-write instead of write-only.
	
Sun Aug  6 20:28:35 1995  Anand Kumria <akumria@ozemail.com.au>

	* [misc/main.c] [include/msdos.h]
	Fixed to return DOS version 6.22, and the correct byte order
	for Windows programs.

Wed Aug  2 12:36:33 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

	* [include/options.h] [memory/global.c] [misc/main.c]
	Make the new IPC run-time selectible, disabling it by default.
	(I think it's only useful for libwine, anyway.)

	* [loader/task.c] [memory/selector.c]
	In FreeSelector(), walk up the stack and fix the frames.

	* [objects/dib.c]
	Missing break statement in DIB_SetImageBits_RLE8().
	In GetDIBits(), set the compression flag in the bitmap info to zero.

	* [windows/dialog.c]
	GetNextDlgGroupItem() needs to treat the first child as if it had
	an implicit WS_GROUP bit set.

Mon Jul 31 15:44:47 EDT 1995 Louis-D. Dubeau <ldd@step.polymtl.ca>

	* [misc/dos_fs.c]
	Quick'n dirty fix for the initialisation of the Z: information
	structure.
diff --git a/misc/shell.c b/misc/shell.c
index ebdfd91..2157470 100644
--- a/misc/shell.c
+++ b/misc/shell.c
@@ -5,6 +5,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <ctype.h>
 #include "windows.h"
 #include "shell.h"
 #include "neexe.h"
@@ -17,7 +18,7 @@
 
 LPKEYSTRUCT	lphRootKey = NULL,lphTopKey = NULL;
 
-static char RootKeyName[]=".classes", TopKeyName[] = "(null)";
+static char RootKeyName[]=".classes", TopKeyName[] = "[top-null]";
 
 /*************************************************************************
  *                        SHELL_RegCheckForRoot()     internal use only
@@ -62,7 +63,7 @@
  */
 LONG RegOpenKey(HKEY hKey, LPCSTR lpSubKey, HKEY FAR *lphKey)
 {
-	LPKEYSTRUCT	lpKey;
+	LPKEYSTRUCT	lpKey,lpNextKey;
 	LPCSTR		ptr;
 	char		str[128];
 	LONG            dwRet;
@@ -71,18 +72,21 @@
         if (dwRet != ERROR_SUCCESS) return dwRet;
 	dprintf_reg(stddeb, "RegOpenKey(%08lX, %p='%s', %p)\n",
 						hKey, lpSubKey, lpSubKey, lphKey);
-	if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;
 	if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
         switch(hKey) {
 	case 0: 
 	  lpKey = lphTopKey; break;
         case HKEY_CLASSES_ROOT: /* == 1 */
+        case 0x80000000:
           lpKey = lphRootKey; break;
         default: 
 	  dprintf_reg(stddeb,"RegOpenKey // specific key = %08lX !\n", hKey);
 	  lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
         }
-        if (!*lpSubKey)  { *lphKey = hKey; return ERROR_SUCCESS; }
+	if (lpSubKey == NULL || !*lpSubKey)  { 
+	  *lphKey = hKey; 
+	  return ERROR_SUCCESS; 
+	}
         while(*lpSubKey) {
           ptr = strchr(lpSubKey,'\\');
           if (!ptr) ptr = lpSubKey + strlen(lpSubKey);
@@ -91,8 +95,11 @@
           lpSubKey = ptr; 
           if (*lpSubKey) lpSubKey++;
 	  
-	  lpKey = lpKey->lpSubLvl;
-          while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { lpKey = lpKey->lpNextKey; }
+	  lpNextKey = lpKey->lpSubLvl;
+          while(lpKey != NULL && strcmp(lpKey->lpSubKey, str) != 0) { 
+          	lpKey = lpNextKey;
+          	if (lpKey) lpNextKey = lpKey->lpNextKey;
+          }
           if (lpKey == NULL) {
 	    dprintf_reg(stddeb,"RegOpenKey: key %s not found!\n",str);
 	    return ERROR_BADKEY;
@@ -119,18 +126,21 @@
 	dwRet = SHELL_RegCheckForRoot();
         if (dwRet != ERROR_SUCCESS) return dwRet;
 	dprintf_reg(stddeb, "RegCreateKey(%08lX, '%s', %p)\n",	hKey, lpSubKey, lphKey);
-	if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;
 	if (lphKey == NULL) return ERROR_INVALID_PARAMETER;
         switch(hKey) {
 	case 0: 
 	  lpKey = lphTopKey; break;
         case HKEY_CLASSES_ROOT: /* == 1 */
+        case 0x80000000:
           lpKey = lphRootKey; break;
         default: 
 	  dprintf_reg(stddeb,"RegCreateKey // specific key = %08lX !\n", hKey);
 	  lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
         }
-        if (!*lpSubKey)  { *lphKey = hKey; return ERROR_SUCCESS; }
+	if (lpSubKey == NULL || !*lpSubKey)  { 
+	  *lphKey = hKey; 
+	  return ERROR_SUCCESS;
+	}
         while (*lpSubKey) {
           dprintf_reg(stddeb, "RegCreateKey: Looking for subkey %s\n", lpSubKey);
           ptr = strchr(lpSubKey,'\\');
@@ -210,7 +220,7 @@
     LONG       	dwRet;
     dprintf_reg(stddeb, "RegSetValue(%08lX, '%s', %08lX, '%s', %08lX);\n",
 		hKey, lpSubKey, dwType, lpVal, dwIgnored);
-    if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;
+    /*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
     if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
     if ((dwRet = RegOpenKey(hKey, lpSubKey, &hRetKey)) != ERROR_SUCCESS) {
 	dprintf_reg(stddeb, "RegSetValue // key not found ... so create it !\n");
@@ -240,7 +250,7 @@
 	int			size;
 	dprintf_reg(stddeb, "RegQueryValue(%08lX, '%s', %p, %p);\n",
 							hKey, lpSubKey, lpVal, lpcb);
-	if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;
+	/*if (lpSubKey == NULL) return ERROR_INVALID_PARAMETER;*/
 	if (lpVal == NULL) return ERROR_INVALID_PARAMETER;
 	if (lpcb == NULL) return ERROR_INVALID_PARAMETER;
         if (!*lpcb) return ERROR_INVALID_PARAMETER;
@@ -285,12 +295,12 @@
 	case 0: 
 	  lpKey = lphTopKey; break;
         case HKEY_CLASSES_ROOT: /* == 1 */
+        case 0x80000000:
           lpKey = lphRootKey; break;
         default: 
 	  dprintf_reg(stddeb,"RegEnumKey // specific key = %08lX !\n", hKey);
 	  lpKey = (LPKEYSTRUCT)GlobalLock(hKey);
         }
-
         lpKey = lpKey->lpSubLvl;
         while(lpKey != NULL){
           if (!dwSubKey){
@@ -301,7 +311,7 @@
 	    return ERROR_SUCCESS;
 	  }
           dwSubKey--;
-	  lpKey = lpKey->lpNextKey;
+          lpKey = lpKey->lpNextKey;
         }
 	dprintf_reg(stddeb, "RegEnumKey: key not found!\n");
 	return ERROR_INVALID_PARAMETER;
@@ -351,30 +361,75 @@
 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, int iShowCmd)
 {
     char cmd[400];
+    char *p,*x;
+    long len;
+    char subclass[200];
+    /* OK. We are supposed to lookup the program associated with lpFile,
+     * then to execute it using that program. If lpFile is a program,
+     * we have to pass the parameters. If an instance is already running,
+     * we might have to send DDE commands.
+     */
     dprintf_exec(stddeb, "ShellExecute(%4X,'%s','%s','%s','%s',%x)\n",
 		hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
 		lpParameters ? lpParameters : "<null>", 
 		lpDirectory ? lpDirectory : "<null>", iShowCmd);
-    if(lpOperation && !strcasecmp(lpOperation,"print"))
-    {
-        fprintf(stderr, "Shell print %s: not supported\n", lpFile);
-    	return 2; /* file not found */
+    if (lpFile==NULL) return 0; /* should not happen */
+    if (lpOperation==NULL) /* default is open */
+      lpOperation="open";
+    p=strrchr(lpFile,'.');
+    if (p!=NULL) {
+      x=p; /* the suffixes in the register database are lowercased */
+      while (*x) {*x=tolower(*x);x++;}
     }
-    if(lpOperation && !strcasecmp(lpOperation,"open"))
-    {
-        fprintf(stderr, "ShellExecute: Unknown operation %s\n",lpOperation);
-        return 2;
-    }
-    /* OK. We are supposed to lookup the program associated with lpFile,
-       then to execute it using that program. If lpFile is a program,
-       we have to pass the parameters. If an instance is already running,
-       we might have to send DDE commands.
-       This implementation does none of that. It assumes lpFile is a program.
-       Plain WinExec will do what we need */
-    if(lpParameters)
+    if (p==NULL || !strcmp(p,".exe")) {
+      p=".exe";
+      if (lpParameters) {
         sprintf(cmd,"%s %s",lpFile,lpParameters);
-    else
+      } else {
         strcpy(cmd,lpFile);
+      }
+    } else {
+      len=200;
+      if (RegQueryValue(HKEY_CLASSES_ROOT,p,subclass,&len)==ERROR_SUCCESS) {
+	if (len>20)
+	  fprintf(stddeb,"ShellExecute:subclass with len %ld? (%s), please report.\n",len,subclass);
+	subclass[len]='\0';
+	strcat(subclass,"\\shell\\");
+	strcat(subclass,lpOperation);
+	strcat(subclass,"\\command");
+	dprintf_exec(stddeb,"ShellExecute:looking for %s.\n",subclass);
+	len=400;
+	if (RegQueryValue(HKEY_CLASSES_ROOT,subclass,cmd,&len)==ERROR_SUCCESS) {
+	  char *t;
+	  dprintf_exec(stddeb,"ShellExecute:...got %s\n",cmd);
+	  cmd[len]='\0';
+	  t=strstr(cmd,"%1");
+	  if (t==NULL) {
+	    strcat(cmd," ");
+	    strcat(cmd,lpFile);
+	  } else {
+	    char *s;
+	    s=malloc(len+strlen(lpFile)+10);
+	    strncpy(s,cmd,t-cmd);
+	    strcat(s,lpFile);
+	    strcat(s,t+2);
+	    strcpy(cmd,s);
+	    free(s);
+	  }
+	  /* does this use %x magic too? */
+	  if (lpParameters) {
+	    strcat(cmd," ");
+	    strcat(cmd,lpParameters);
+	  }
+	} else {
+	  fprintf(stddeb,"ShellExecute: No %s\\shell\\%s\\command found for \"%s\" suffix.\n",subclass,lpOperation,p);
+	  return 14; /* unknown type */
+	}
+      } else {
+	fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
+	return 14; /* file not found */
+      }
+    }
     return WinExec(cmd,iShowCmd);
 }