home *** CD-ROM | disk | FTP | other *** search
- /**
- .File
- Multi.c
- .Name
- MultiSelect ListBox for Visual Basic
- .Author
- Dan Rogers
- .What
- custom visual basic control for multi select list box
- .How
- Read-On, man...
- **/
-
- #define NOCOMM
- #include <windows.h>
-
- #include <vbapi.h>
-
- #define CTL_DATA // To declare static data in multi.h
- #include "multi.h"
-
-
- /*
- Standard Error Values
- */
- #define ERR_None 0
- #define ERR_InvPropVal 380 /* Error$(380) = "Invalid property value" */
-
-
- /* Local Prototypes */
-
-
- /* Event Procedure Parameter Profiles */
- typedef struct tagPARAMS3 /* used in fireback */
- {
- LPLONG Value;
- LPINT Offset;
- HLSTR ClickString;
- LPVOID Index; /* Reserve space for index parameter to array ctl */
- } PARAMS3;
-
- typedef struct tagPARAMS4 /* used in click */
- {
- LPLONG Value;
- LPINT Selected;
- LPINT Offset;
- HLSTR ClickString;
- LPVOID Index; /* Reserve space for index parameter to array ctl */
- } PARAMS4;
-
-
- /****************************************/
- /* MultiSelectListBox Control Procedure */
- /****************************************/
- LONG FAR PASCAL _export MultiCtlProc
- (
- HCTL hctl,
- HWND hwnd,
- USHORT msg,
- USHORT wp,
- LONG lp
- )
- {
- LONG lResult;
- LPLONG longer;
- LONG args;
- LONG index;
- PARAMS4 params4;
- PARAMS3 params3;
- HSZ item;
- LPSTR string;
- LONG ret;
- int len;
- USHORT newlen;
- ERR err;
- int i;
- WPARAM offset;
- int selected;
- LONG dataval;
- LPSTR lpstr;
- int oldindex;
- char buffer[132];
-
-
- /* Message pre-processing */
- switch (msg)
- {
-
- /* simple click processing */
- case WM_LBUTTONUP:
- case WM_LBUTTONDBLCLK:
-
- /* make sure something is there (empty list box no go)*/
- len = LOWORD(SendMessage(hwnd, LB_GETCOUNT, (WPARAM)0, 0L));
- if ( len <= 0 )
- return(0);
- len = LOWORD(SendMessage(hwnd, LB_GETSELCOUNT, 0, 0L));
- if (len > 1)
- return(0);
-
- /* What is the caret index, just clicked, has to be here */
- offset = LOWORD(SendMessage (hwnd, LB_GETCARETINDEX, (WPARAM) 0, 0L));
- oldindex = offset;
-
- /* determine if the selection is currently selected */
- selected = (int)SendMessage(hwnd, LB_GETSEL, (WPARAM) offset, 0L);
- if (selected > 0)
- selected = -1;
-
- /* how long is it (would like to allocate, but for now 132 limit) */
- len = LOWORD(SendMessage(hwnd, LB_GETTEXTLEN, (WPARAM)offset, 0L));
- if ( len > 131 || len <= 0 )
- return (0);
- lpstr = buffer;
-
- /* go and get it into the buffer */
- len = (int)SendMessage(hwnd, LB_GETTEXT, (WPARAM) offset, (LPARAM)(LPCSTR) lpstr );
- if ( len > 131 || len <= 0)
- return(0);
- dataval = SendMessage(hwnd, LB_GETITEMDATA, (WPARAM)offset, 0L);
- if (dataval == LB_ERR)
- dataval = -1;
- buffer[len] = (char)NULL;
-
- /* make a VB string out of it */
- newlen = (USHORT) len;
- params4.ClickString = VBCreateHlstr((LPVOID)lpstr, (USHORT)newlen);
- if ( params4.ClickString == (HLSTR) NULL)
- return (380);
- params4.Offset = &offset;
- params4.Selected = &selected;
- params4.Value = &dataval;
-
- err = VBFireEvent(hctl, EVENT_MULTI_CLICK, ¶ms4);
-
- /* user can modify the string, value in the function */
- /* Not allowed to null it out. */
- if (!err)
- {
- if (params4.ClickString == (HLSTR) NULL)
- return (380);
- len = VBGetHlstrLen(params4.ClickString);
- if (len > 131)
- return(380);
- lpstr = VBDerefHlstr(params4.ClickString);
- if (lpstr)
- { string = buffer;
- for ( i = 0; i < len; i ++ )
- {
- *(string+i) = *(lpstr + i);
- if ( *(string + i) == (char) NULL)
- break;
- }
- }
- else
- *buffer = (char)NULL;
-
- buffer[len] = (char)NULL;
- SendMessage (hwnd, WM_SETREDRAW, (WPARAM)0, (LPARAM)0);
- SendMessage ( hwnd, LB_DELETESTRING, (WPARAM)oldindex, (LPARAM)0);
-
- if ( *buffer != (char)NULL)
- {
- SendMessage( hwnd, LB_INSERTSTRING, (WPARAM) oldindex, (LPARAM) string);
- SendMessage(hwnd, LB_SETCARETINDEX, (WPARAM) oldindex, (LPARAM) 0);
- if ( selected )
- SendMessage(hwnd, LB_SETSEL, (WPARAM)TRUE, MAKELPARAM(oldindex, 0));
- }
- SendMessage(hwnd, WM_SETREDRAW, (WPARAM)1, (LPARAM)0);
- }
- if ( params4.ClickString != NULL )
- VBDestroyHlstr(params4.ClickString);
-
- break;
-
- case VBM_SETPROPERTY:
- /* add property setting here for the properties that */
- /* require support of messages (list, sellist, selcnt, listcnt) */
- switch (wp)
- {
- case IPROP_MULTI_SELCOUNT:
- /* may zero the selected list */
- if ( (int)lp )
- return(380);
- SendMessage(hwnd, LB_SETSEL, 0, MAKELPARAM(-1,0));
- break;
-
- case IPROP_MULTI_LISTCOUNT:
- /* may zero the selected list */
- if ( (int)lp )
- return(380);
- SendMessage(hwnd, LB_RESETCONTENT, 0, 0L);
- break;
-
- case IPROP_MULTI_FIREBACK:
- /* setting this property causes the SelectDump event */
- /* to be fired for each occurence of selected items */
- {
- int count;
- long dval;
- int loop;
- int top, len;
- int hunt;
- HGLOBAL hg;
-
- count = LOWORD(SendMessage(hwnd, LB_GETSELCOUNT, 0, 0L));
- if ( count == 0 )
- return(0);
- params3.Value = &dval;
- params3.Offset = &loop;
- for (i = 1; i <= count; i++)
- {
- top = LOWORD(SendMessage(hwnd, LB_GETCOUNT, 0, 0L));
- hunt = 0;
- if (i > top)
- return(0);
- for ( loop = 0; loop < top; loop ++)
- {
- len = LOWORD(SendMessage(hwnd, LB_GETSEL, (WPARAM)loop, 0L));
- if ( len > 0 )
- {
- hunt ++;
- if (hunt == i )
- break;
- }
- }
- if (loop >= top)
- return(382);
- len = LOWORD(SendMessage(hwnd, LB_GETTEXTLEN, (WPARAM)loop, 0L));
- hg = GlobalAlloc(GMEM_FIXED, (DWORD)(count + 1));
- if (!hg)
- return(383);
- lpstr = (LPSTR) GlobalLock(hg);
- SendMessage(hwnd, LB_GETTEXT, (WPARAM)loop, (LONG) lpstr);
- params3.ClickString = VBCreateHlstr((LPVOID)lpstr, (USHORT)len);
- if (params3.ClickString == NULL)
- return(384);
- dval = SendMessage(hwnd, LB_GETITEMDATA, (WPARAM)loop, 0L);
- err = VBFireEvent(hctl, EVENT_MULTI_SELECTDUMP, ¶ms3);
- if (params3.ClickString != NULL)
- VBDestroyHlstr(params3.ClickString);
- GlobalUnlock(hg);
- GlobalFree (hg);
- }
- }
- break;
-
- case IPROP_MULTI_LIST:
- /* can be used as additem alternative */
- /* this string array property uses no actual */
- /* data, but rather stores items in the list box */
- {
- int count;
- int i;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
-
- i = (int)lpDs->index[0].data;
- count = LOWORD(SendMessage(hwnd,LB_GETCOUNT, 0, 0L));
- if (i > count || i < 0 )
- i = -1;
- count = 0;
- i = (int)SendMessage(hwnd, LB_INSERTSTRING, (WPARAM)i, (LONG) (lpDs->data));
- if (i == LB_ERR || i == LB_ERRSPACE)
- return ( 380 );
- SendMessage(hwnd, LB_SETITEMDATA, (WPARAM)i, (LONG)(LPLONG)&count);
- }
- break;
- }
- break;
-
- case VBM_GETPROPERTY:
- switch(wp)
- {
- case IPROP_MULTI_SELCOUNT:
- *((int far *)lp) = (int)SendMessage(hwnd, LB_GETSELCOUNT, 0, 0L);
- break;
-
- case IPROP_MULTI_LISTCOUNT:
- *((int far *)lp) = (int)SendMessage(hwnd, LB_GETCOUNT, 0, 0L);
- break;
-
- case IPROP_MULTI_LIST:
- {
- long count;
- LONG i;
- HGLOBAL hg;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
- i = lpDs->index[0].data;
- count = SendMessage(hwnd,LB_GETCOUNT, 0, 0L);
- if (i > count || i < 0 )
- return(381);
- count = SendMessage(hwnd, LB_GETTEXTLEN, (WPARAM)i, 0L);
- hg = GlobalAlloc(GMEM_FIXED, (DWORD)(count + 1));
- if (!hg)
- return(380);
- lpstr = (LPSTR) GlobalLock(hg);
- SendMessage(hwnd, LB_GETTEXT, (WPARAM)i, (LONG) lpstr);
- lpDs->data = (LONG)VBCreateHsz((_segment)hctl, lpstr);
- GlobalUnlock(hg);
- GlobalFree (hg);
- break;
- }
-
- case IPROP_MULTI_SELLIST:
- {
- int count;
- int loop, i;
- int top, len;
- int hunt;
- HGLOBAL hg;
- LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
- i = (int)lpDs->index[0].data;
- count = LOWORD(SendMessage(hwnd,LB_GETSELCOUNT, 0, 0L));
- if (i > count || i < 1 )
- return(381);
- top = LOWORD(SendMessage(hwnd, LB_GETCOUNT, 0, 0L));
- hunt = 0;
- for ( loop = 0; loop < top; loop ++)
- {
- len = LOWORD(SendMessage(hwnd, LB_GETSEL, (WPARAM)loop, 0L));
- if ( len )
- {
- hunt ++;
- if (hunt == i )
- break;
- }
- }
- if (loop == top)
- return(381);
- len = LOWORD(SendMessage(hwnd, LB_GETTEXTLEN, (WPARAM)loop, 0L));
- hg = GlobalAlloc(GMEM_FIXED, (DWORD)(count + 1));
- if (!hg)
- return(380);
- lpstr = (LPSTR) GlobalLock(hg);
- SendMessage(hwnd, LB_GETTEXT, (WPARAM)loop, (LONG) lpstr);
- lpDs->data = (LONG)VBCreateHsz((_segment)hctl, lpstr);
- GlobalUnlock(hg);
- GlobalFree (hg);
- break;
- }
- }
- break;
-
- /* code to handle the optional methods for controls... */
- case VBM_METHOD:
- switch ( wp )
- {
- /* AddItem method: add item to list */
- case METH_ADDITEM:
- longer = (LPLONG )lp;
- args = longer[0];
- item = (HSZ)longer[1];
- if (args > 2 )
- index = longer[2];
- else
- index = -1;
- string = VBDerefHsz(item);
-
- /* later on, if sorted property is set, use */
- /* the addstring method - honors sorted property */
- ret = SendMessage ( hwnd, LB_INSERTSTRING, (WPARAM)index, (LPARAM)(LPCSTR)string);
- if ( ret == LB_ERR || ret == LB_ERRSPACE )
- return (ret);
- index = ret;
- ret = SendMessage( hwnd, LB_SETITEMDATA, (WPARAM)index, 0L);
- return (0);
-
- /* Method to remove specific item from the list */
- case METH_REMOVEITEM:
- longer = (LPLONG )lp;
- args = longer[0];
- index = longer[1];
- ret = SendMessage ( hwnd, LB_DELETESTRING, (WPARAM)index, (LPARAM)0);
- return (0);
-
- default:
- break;
- }
- break;
-
- case VBN_DRAWITEM:
- return 0;
-
- }
-
- /* Default processing: Pass thru to let VB handle it - talks to control */
- lResult = VBDefControlProc(hctl, hwnd, msg, wp, lp);
-
- /* could not get VBN_COMMAND: case VBN_CLICKED */
- /* to work properly as reflection of WM_COMMAND */
- /* sent by control. Implemented click as a post */
- /* control class processing job based upon the */
- /* value of the original message (somehow the */
- /* msg arg is altered after the default p call */
- /*switch(oldmsg)
- {
-
- default:
- break;
-
- } */
- /*Message post-processing:*/
-
- switch (msg)
- {
- case WM_DESTROY:
- break;
-
- }
-
- return lResult;
- }
-