Release 960728

Sun Jul 28 17:57:19 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [loader/task.c] [include/task.h]
	Implemented SwitchStackTo()/SwitchStackBack().

	* [include/wintypes.h] [loader/main.c]
	Added __winelib variable to distinguish between emulator and
 	library at run-time. Later on, this should avoid some
 	recompilations when building Winelib.

	* [windows/property.c]
	Implemented Win32 functions for window properties.

Fri Jul 26 18:00:00 1996  Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [controls/listbox.c]
	Implemented LBS_SORT style, WM_COMPAREITEM, and WM_DELETEITEM
	messages.

	* [controls/menu.c]
	Call TranslateMessage() to enable shortcuts (on WM_CHAR).

	* [include/cursoricon.h]
	Moved #pragma pack(1) back to where it belongs.

	* [objects/palette.c]
	RealizeDefaultPalette() maps to system colors only.
	Do not broadcast palette notifications when in TrueColor.

	* [objects/color.c] [include/palette.h]
	Miscellaneous optimizations. Had to fix several
	"improvements" made to my patch for previous release.

	* [objects/dib.c]
	Reverse dib bits order for 24-bit SetDIBits().

	* [objects/dc.c]
	GetDeviceCaps() does not return RC_PALETTE when in TrueColor.

	* [windows/scroll.c]
	Scroll update region too.

	* [windows/message.c]
	Include QS_MOUSE into the event mask for nonclient mouse
	message filter. Fixes problems with Word 6 freezing when
	mouse hits nonclient area.

	* [windows/win.c] 
	Allow top-level windows to be linked as HWND_TOP in CreateWindow().

	* [windows/winpos.c] [windows/mdi.c]
	Attempt to fix control menu duplication.

Fri Jul 26 09:49:35 1996  Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>

	* [files/drive.c]
	GetDriveType32A(): return value for CDROM fixed.

	* [files/file.c]
	SearchPath* added.

	* [if1632/gdi32.spec] [objects/brush.c]
	SetBrushOrgEx() added.

	* [loader/pe_resource.c]
	If even loading the default entry fails, we just use the first
	entry from the resource directory.

	[loader/task.c]
	SetSigHandler() stub added, Paradox 4.5 now starts up.

	* [misc/comm.c] [include/windows.h] [if1632/kernel32.spec]
	COMM functions updated to win32, not complete.

	* [misc/lstr.c]
	FormatMessageA partially implemented.

	* [include/miscemu.h] [memory/selector.c]
	  [memory/global.c] [miscemu/dosmem.c]
	DOS memory handling changed: 1MB preallocated block, real-mode
	segment handling possible, SetSelectorBase into lower physical 1MB
	possible.

	* [miscemu/dpmi.c]
	Real-mode segments changed, real-mode int 21,ax=6506 added.
	AX=0x0303 added.

	* [multimedia/time.c]
	Fixed bug in killTimer.

	* [objects/bitmap.c]
	LoadImageA partially implemented.

Wed Jul 24 18:20:24 1996  Albrecht Kleine  <kleine@ak.sax.de>

	* [include/dde_mem.h][include/dde_proc.h]
	  [ipc/dde_atom.c][ipc/dde_proc.c][windows/message.c]
	  [ipc/generic_hash.h][library/miscstubs.c]
	Changes for error free compilation using "--with-ipc":
	replaced some names with *16-equivalent (e.g. MSG to MSG16),
	modified prototype of function DDE_GlobalFree() .

	* [objects/palette.c]
	Added check for metafile-DC in GDISelectPalette(),
	GDIRealizePalette(),RealizeDefaultPalette() and
	IsDCCurrentPalette().

Tue Jul 23 22:46:53 1996  Andrew Lewycky <plewycky@oise.utoronto.ca>

	* [controls/edit.c]
	EDIT_WM_Create: Don't EDIT_EM_ReplaceSel if created with lParam = "",
	fixes Winhelp.

	* [windows/dialog.c]
	DIALOG_CreateIndirect: Initialise dlgProc before creating children.
diff --git a/controls/listbox.c b/controls/listbox.c
index b3a5b8d..1cbb28c 100644
--- a/controls/listbox.c
+++ b/controls/listbox.c
@@ -3,15 +3,17 @@
  * 
  * Copyright  Martin Ayotte, 1993
  *            Constantine Sapuntzakis, 1995
- * 	      Alex Korobka, 1995 
+ * 	      Alex Korobka, 1995, 1996 
  * 
  */
 
  /*
   * FIXME: 
-  * - check if multi-column listboxes work
-  * - implement more messages and styles 
-  * - implement caret for LBS_EXTENDEDSEL
+  * - proper scrolling for multicolumn style
+  * - anchor and caret for LBS_EXTENDEDSEL
+  * - proper selection with keyboard
+  * - how to handle (LBS_EXTENDEDSEL | LBS_MULTIPLESEL) style
+  * - support for LBS_NOINTEGRALHEIGHT and LBS_OWNERDRAWVARIABLE styles
   */
 
 #include <stdio.h>
@@ -27,6 +29,7 @@
 #include "drive.h"
 #include "file.h"
 #include "heap.h"
+#include "stackframe.h"
 #include "stddebug.h"
 #include "debug.h"
 #include "xmalloc.h"
@@ -43,6 +46,10 @@
 #define LBMM_EDGE   4    /* distance inside box which is same as moving mouse
 			    outside box, to trigger scrolling of LB */
 
+#define MATCH_SUBSTR            2
+#define MATCH_EXACT             1
+#define MATCH_NEAREST           0
+
 static void ListBoxInitialize(LPHEADLIST lphl)
 {
   lphl->lpFirst        = NULL;
@@ -267,6 +274,21 @@
   return LB_ERR;
 }
 
+BOOL lbDeleteItemNotify(LPHEADLIST lphl, LPLISTSTRUCT lpls)
+{
+  /* called only for owner drawn listboxes */
+
+  DELETEITEMSTRUCT16   delItem;
+
+  delItem.CtlType = lphl->DrawCtlType;
+  delItem.CtlID   = lphl->CtlID;
+  delItem.itemID  = lpls->mis.itemID;
+  delItem.hwndItem= lphl->hSelf;
+  delItem.itemData= lpls->mis.itemData;
+
+  return (BOOL) SendMessage16(lphl->hParent, WM_DELETEITEM, (WPARAM)lphl->CtlID,
+                                          (LPARAM)MAKE_SEGPTR(&delItem));
+}
 
 void ListBoxAskMeasure(LPHEADLIST lphl, LPLISTSTRUCT lpls)  
 {
@@ -306,7 +328,97 @@
   return lplsnew;
 }
 
+int ListBoxAskCompare(LPHEADLIST lphl, int startItem, SEGPTR matchData, BOOL exactMatch )
+{
+ /*  Do binary search for sorted listboxes. Linked list item storage sort of 
+  *  defeats the purpose ( forces to traverse item list all the time ) but M$ does it this way...
+  *
+  *  MATCH_NEAREST (0) - return position for insertion - for all styles
+  *  MATCH_EXACT   (1) - search for an item, return index or LB_ERR 
+  *  MATCH_SUBSTR  (2) - same as exact match but with strncmp for string comparision
+  */
 
+ COMPAREITEMSTRUCT16    itemCmp;
+ LPLISTSTRUCT		currentItem = NULL;
+ LPCSTR			matchStr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(matchData):NULL;
+ int                    head, pos = -1, tail, loop = 1;
+ short                  b = 0, s_length = 0;
+
+ /* check if empty */
+
+ if( !lphl->ItemsCount )
+    return (exactMatch)? LB_ERR: 0;
+
+ /* set up variables */
+
+ if( exactMatch == MATCH_NEAREST )
+     startItem = 0;
+ else if( ++startItem ) 
+   {
+     loop = 2;
+     if( startItem >= lphl->ItemsCount ) startItem = lphl->ItemsCount - 1;
+   }
+
+ if( exactMatch == MATCH_SUBSTR && lphl->HasStrings )
+   {
+     s_length = strlen( matchStr );
+     if( !s_length ) return 0; 		        /* head of the list - empty string */
+   }
+
+ head = startItem; tail = lphl->ItemsCount - 1;
+
+ dprintf_listbox(stddeb,"AskCompare: head = %i, tail = %i, data = %08x\n", head, tail, (unsigned)matchData );
+
+ itemCmp.CtlType        = lphl->DrawCtlType;
+ itemCmp.CtlID          = lphl->CtlID;
+ itemCmp.hwndItem       = lphl->hSelf;
+
+ /* search from startItem */
+
+ while ( loop-- )
+  {
+    while( head <= tail )
+     {
+       pos = (tail + head)/2;
+       currentItem = ListBoxGetItem( lphl, pos );
+
+       if( lphl->HasStrings )
+	 {
+           b = ( s_length )? strncasecmp( currentItem->itemText, matchStr, s_length)
+                           : strcasecmp( currentItem->itemText, matchStr);
+	 }
+       else
+         {
+           itemCmp.itemID1      = pos;
+           itemCmp.itemData1    = currentItem->mis.itemData;
+           itemCmp.itemID2      = -1;
+           itemCmp.itemData2    = matchData;
+
+           b = SendMessage16( lphl->hParent, WM_COMPAREITEM, (WPARAM)lphl->CtlID, 
+                                                             (LPARAM)MAKE_SEGPTR(&itemCmp) );
+         }
+
+       if( b == 0 ) 
+           return pos;  /* found exact match */
+       else
+         if( b < 0 ) head = ++pos;
+         else
+           if( b > 0 ) tail = pos - 1;
+     }
+
+    /* reset to search from the first item */
+    head = 0; tail = startItem - 1;
+  }
+
+ dprintf_listbox(stddeb,"\t-> pos = %i\n", pos );
+
+ /* if we got here match is not exact */
+
+ if( pos < 0 ) pos = 0;
+ else if( pos > lphl->ItemsCount ) pos = lphl->ItemsCount;
+
+ return (exactMatch)? LB_ERR: pos;
+}
 
 int ListBoxInsertString(LPHEADLIST lphl, UINT uIndex, LPCSTR newstr)
 {
@@ -371,16 +483,14 @@
 }
 
 
-int ListBoxAddString(LPHEADLIST lphl, LPCSTR newstr)
+int ListBoxAddString(LPHEADLIST lphl, SEGPTR itemData)
 {
-    UINT pos = (UINT) -1;
-    
-    if (lphl->HasStrings && (lphl->dwStyle & LBS_SORT)) {
-	LPLISTSTRUCT lpls = lphl->lpFirst;
-	for (pos = 0; lpls != NULL; lpls = lpls->lpNext, pos++)
-	    if (strcmp(lpls->itemText, newstr) >= 0)
-		break;
-    }
+    UINT 	pos = (UINT) -1;
+    LPCSTR	newstr = (lphl->HasStrings)?(LPCSTR)PTR_SEG_TO_LIN(itemData):(LPCSTR)itemData;
+
+    if ( lphl->dwStyle & LBS_SORT ) 
+	 pos = ListBoxAskCompare( lphl, -1, itemData, MATCH_NEAREST );
+
     return ListBoxInsertString(lphl, pos, newstr);
 }
 
@@ -438,8 +548,13 @@
   if (lpls == NULL) return LB_ERR;
 
   if (uIndex == 0)
+  {
+    if( lphl->OwnerDrawn )
+        lbDeleteItemNotify( lphl, lpls);
     lphl->lpFirst = lpls->lpNext;
-  else {
+  }
+  else 
+  {
     LPLISTSTRUCT lpls2 = NULL;
     for(Count = 0; Count < uIndex; Count++) {
       if (lpls->lpNext == NULL) return LB_ERR;
@@ -447,6 +562,8 @@
       lpls2 = lpls;
       lpls = (LPLISTSTRUCT)lpls->lpNext;
     }
+    if( lphl->OwnerDrawn )
+	lbDeleteItemNotify( lphl, lpls);
     lpls2->lpNext = lpls->lpNext;
   }
 
@@ -463,28 +580,43 @@
   return lphl->ItemsCount;
 }
 
-
-int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+int lbFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr, BOOL match)
 {
+  /*  match is either MATCH_SUBSTR or MATCH_EXACT */
+
   LPLISTSTRUCT lpls;
   UINT	       Count;
-  UINT         First = nFirst + 1;
+  UINT         First      = nFirst + 1;
+  int	       s_length   = 0;
   LPSTR        lpMatchStr = (LPSTR)MatchStr;
 
   if (First > lphl->ItemsCount) return LB_ERR;
 
-  if (lphl->HasStrings) lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
-  
+  if (lphl->dwStyle & LBS_SORT )
+      return ListBoxAskCompare( lphl, nFirst, MatchStr, match );
+
+  if (lphl->HasStrings ) 
+  {
+    lpMatchStr = PTR_SEG_TO_LIN(MatchStr);
+
+    if( match == MATCH_SUBSTR )
+    {
+      s_length = strlen(lpMatchStr);
+      if( !s_length ) return (lphl->ItemsCount)?0:LB_ERR;
+    }
+  }
+
   lpls = ListBoxGetItem(lphl, First);
   Count = 0;
-  while(lpls != NULL) {
-    if (lphl->HasStrings) {
-      if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
-    } else if (lphl->dwStyle & LBS_SORT) {
-      /* XXX Do a compare item */
+  while(lpls != NULL) 
+  {
+    if (lphl->HasStrings) 
+    {
+      if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
+                       : !strcasecmp(lpls->itemText, lpMatchStr)  ) return Count;
     }
     else
-      if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
+      if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
 
     lpls = lpls->lpNext;
     Count++;
@@ -494,14 +626,16 @@
   Count = 0;
   lpls = lphl->lpFirst;
 
-  while (Count < First) {
-    if (lphl->HasStrings) {
-      if (strstr(lpls->itemText, lpMatchStr) == lpls->itemText) return Count;
-    } else if (lphl->dwStyle & LBS_SORT) {
-      /* XXX Do a compare item */
-    } else {
-      if (lpls->mis.itemData == (DWORD)lpMatchStr) return Count;
+  while (Count < First) 
+  {
+    if (lphl->HasStrings) 
+    {
+      if ( ( s_length )? !strncasecmp(lpls->itemText, lpMatchStr, s_length)
+                       : !strcasecmp(lpls->itemText, lpMatchStr)  ) return Count;
     }
+    else
+      if ( lpls->mis.itemData == (DWORD)lpMatchStr ) return Count;
+    
     lpls = lpls->lpNext;
     Count++;
   }
@@ -509,6 +643,15 @@
   return LB_ERR;
 }
 
+int ListBoxFindString(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+{
+  return lbFindString(lphl, nFirst, MatchStr, MATCH_SUBSTR );
+}
+
+int ListBoxFindStringExact(LPHEADLIST lphl, UINT nFirst, SEGPTR MatchStr)
+{
+  return lbFindString(lphl, nFirst, MatchStr, MATCH_EXACT );
+}
 
 int ListBoxResetContent(LPHEADLIST lphl)
 {
@@ -523,7 +666,9 @@
     for(i = 0; i < lphl->ItemsCount; i++) {
       lpls = lphl->lpFirst;
       if (lpls == NULL) return LB_ERR;
-      
+
+      if (lphl->OwnerDrawn) lbDeleteItemNotify(lphl, lpls);
+
       lphl->lpFirst = lpls->lpNext;
       if (lpls->hData != 0) LIST_HEAP_FREE(lphl, lpls->hData);
       free(lpls);
@@ -603,12 +748,13 @@
 
 LONG ListBoxDirectory(LPHEADLIST lphl, UINT attrib, LPCSTR filespec)
 {
-    char temp[16], mask[13];
+    char 	mask[13];
+    char*	temp = NULL;
+    const char*	ptr;
+    int 	skip, count;
+    LONG 	ret;
+    DOS_DIRENT 	entry;
     char *path, *p;
-    const char *ptr;
-    int skip, count;
-    LONG ret;
-    DOS_DIRENT entry;
 
     dprintf_listbox(stddeb, "ListBoxDirectory: '%s' %04x\n", filespec, attrib);
     if (!filespec) return LB_ERR;
@@ -616,11 +762,13 @@
     path = xstrdup(ptr);
     p = strrchr( path, '/' );
     *p++ = '\0';
-    if (!(ptr = DOSFS_ToDosFCBFormat( p )))
+    if (!(ptr = DOSFS_ToDosFCBFormat( p )) || 
+        !(temp = SEGPTR_ALLOC( sizeof(char) * 16 )) )
     {
         free( path );
         return LB_ERR;
     }
+
     strcpy( mask, ptr );
 
     dprintf_listbox(stddeb, "ListBoxDirectory: path=%s mask=%s\n", path, mask);
@@ -636,7 +784,7 @@
             {
                 sprintf(temp, "[%s]", DOSFS_ToDosDTAFormat( entry.name ) );
                 AnsiLower( temp );
-                if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+                if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
             }
         }
         else  /* not a directory */
@@ -647,9 +795,11 @@
             {
                 strcpy( temp, DOSFS_ToDosDTAFormat( entry.name ) );
                 AnsiLower( temp );
-                if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+                if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
             }
         }
+
+        dprintf_listbox(stddeb,"\tn - %i, file '%s'\n", count, temp); 
     }
     if (attrib & DDL_DRIVES)
     {
@@ -658,10 +808,13 @@
         for (x = 0; x < MAX_DOS_DRIVES; x++, temp[2]++)
         {
             if (DRIVE_IsValid(x))
-                if ((ret = ListBoxAddString(lphl, temp)) == LB_ERR) break;
+                if ((ret = ListBoxAddString(lphl, SEGPTR_GET(temp))) == LB_ERR) break;
         }
     }
+
     free( path );
+    SEGPTR_FREE( temp );
+
     return ret;
 }
 
@@ -1432,10 +1585,7 @@
   WORD  wRet;
   LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
 
-  if (lphl->HasStrings)
-    wRet = ListBoxAddString(lphl, (LPCSTR)PTR_SEG_TO_LIN(lParam));
-  else
-    wRet = ListBoxAddString(lphl, (LPCSTR)lParam);
+  wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
 
   ListBoxUpdateWindow(hwnd,lphl,TRUE);
   return wRet;
@@ -1490,7 +1640,16 @@
 static LONG LBFindString(HWND hwnd, WORD wParam, LONG lParam)
 {
   LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
-  return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
+  return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
+}
+
+/***********************************************************************
+ *           LBFindStringExact
+ */
+static LONG LBFindStringExact(HWND hwnd, WORD wParam, LONG lParam)
+{
+  LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
+  return lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_EXACT);
 }
 
 /***********************************************************************
@@ -1661,7 +1820,7 @@
   LPHEADLIST lphl = ListBoxGetStorageHeader(hwnd);
   INT  iRet;
 
-  iRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
+  iRet = lbFindString(lphl, wParam, (SEGPTR)lParam, MATCH_SUBSTR);
 
   if( iRet != LB_ERR)
     {
@@ -1920,6 +2079,7 @@
      case LB_INSERTSTRING: return LBInsertString(hwnd, wParam, lParam);
      case LB_DELETESTRING: return LBDeleteString(hwnd, wParam, lParam);
      case LB_FINDSTRING: return LBFindString(hwnd, wParam, lParam);
+     case LB_FINDSTRINGEXACT: return LBFindStringExact(hwnd, wParam, lParam);
      case LB_GETCARETINDEX: return LBGetCaretIndex(hwnd, wParam, lParam);
      case LB_GETCOUNT: return LBGetCount(hwnd, wParam, lParam);
      case LB_GETCURSEL: return LBGetCurSel(hwnd, wParam, lParam);