DDEPROCS.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*
ddeprocs.c
*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include "ddeinst.h"
#include "ddextrn.h"
#include "dialogs.h"

// function prototype for List synchronization
void SynchronizeLists (HWND);
void SynchronizeListSelection (HWND);

// function prototype for child window creation
void CreateChildren (HWND);

// internal thread counter
int iThreadCount = 0;

/********************************************************************

MainWndProc.

Function that processes the messages sent to the main window.

********************************************************************/

LRESULT APIENTRY MainWndProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
LPARAM lParam) {
BOOL fFlag;

switch (uiMsg) {
case WM_CREATE: {

// Create all of the child windows that are desired.
CreateChildren (hwnd);
break;
}/*endCase*/
case WM_DESTROY: {
PostQuitMessage (0);
return (0L);
}/*endCase*/
case WM_USER_CLOSE_DIALOG: {
if (hwndDialog) {
DestroyWindow (hwndDialog);
hwndDialog = (HWND) NULL;
return (TRUE);
}/*endIf*/
break;
}/*endCase*/
case WM_SIZE: {
/* Need to resize the StatusBar */
if (hwndStatus) {
long lHeight;
int iWidth;
int iHeight;

iWidth = LOWORD (lParam);
iHeight = HIWORD (lParam);
lHeight = GetWindowLong (hwndStatus, GWL_USERDATA);
MoveWindow (hwndStatus, -1, iHeight - (int) lHeight,
iWidth + 2, lHeight + 2, TRUE);
}/*endIf*/
break;
}/*endCase*/
case WM_USER_GET_APPS: {
StartTraverseThread (szUserPath);
return (1L);
}/*endCase*/
case WM_USER_GET_GROUPS: {
StartGroupRetrievalThread ();
return (1L);
}/*endCase*/
case WM_USER_THREAD_DONE: {
iThreadCount++;
if (!fBatch) {
break;
}/*endIf*/
if (iThreadCount == 2) {
PostMessage (ghwndMain, WM_COMMAND,
(WPARAM) MAKELONG (ID_ADDALLBUTTON, BN_CLICKED),
(LPARAM) hwndAddAll);
PostMessage (ghwndMain, WM_COMMAND,
(WPARAM) MAKELONG (ID_ADDGROUP, BN_CLICKED),
(LPARAM) hwndAddGroupButton);
PostMessage (ghwndMain, WM_COMMAND,
(WPARAM) MAKELONG (ID_ADDBUTTON, BN_CLICKED),
(LPARAM) hwndAddButton);
iThreadCount = 0;
}/*endIf*/
break;
}/*endCase*/
case WM_COMMAND: {
switch (HIWORD (wParam)) {
case LBN_SELCHANGE: {
SynchronizeListSelection ((HWND) lParam);
if ((HWND) lParam == hwndCombo) {
EnableWindow (hwndAddGroupButton, TRUE);
}/*endIf*/
break;
}/*endCase*/
case CBN_EDITCHANGE: {
fFlag = (BOOL) GetWindowTextLength (hwndCombo);
EnableWindow (hwndAddGroupButton, fFlag);
break;
}/*endCase*/
case BN_CLICKED: {
switch (LOWORD (wParam)) {
case ID_ADDALLBUTTON: {

// Select all elements in the two lists.
// Under Win 3.x LPARAM of LB_SETSEL is MAKELPARAM (-1, 0)
// Under Win32 it is -1

SendMessage (hwndFileList, LB_SETSEL, (WPARAM) TRUE,
(LPARAM) -1);

// Under Win 3.x LPARAM of LB_SETSEL is MAKELPARAM (-1, 0)
// Under Win32 it is -1

SendMessage (hwndFileList2, LB_SETSEL, (WPARAM) TRUE,
(LPARAM) -1);
break;
}/*endCase*/
case ID_EXITBUTTON: {
PostQuitMessage (0);
break;
}/*endCase*/
case ID_ADDBUTTON: {
// Create the Progress Dialog
hwndDialog = CreateDialog (ghModule,
"ProgressDialog", hwnd, ProgressDlgWndProc);

// Start a thread to add the items
StartAddThread ();
break;
}/*endCase*/
case ID_ADDGROUP: {

// Add the user defined group.
CreateGroup ();
break;
}/*endCase*/
}/*endSwitch*/
break;
}/*endCase*/
}/*endSwitch*/

// Process menu events now.

switch (LOWORD (wParam)) {
case DI_EXIT: {
PostQuitMessage (0);
return (1L);
}/*endCase*/
case DI_ABOUT: {
DialogBox (ghModule, "AboutBox", hwnd,
(DLGPROC) AboutBoxWndProc);
break;
}/*endCase*/
}/*endSwitch*/
break;
}/*endCase*/
}/*endSwitch*/
return (DefWindowProc (hwnd, uiMsg, wParam, lParam));
}/* end MainWndProc */

/********************************************************************

StatusBarWndProc.

Function that manages the Status bar at the bottom of the main
window.

********************************************************************/

LRESULT APIENTRY StatusBarWndProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
LPARAM lParam) {
HDC hdc;
long lHeight;
RECT rc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
POINT pts[6];

switch (uiMsg) {
case WM_CTLCOLORSTATIC: {
SetBkMode ((HDC) wParam, TRANSPARENT);
return ((LRESULT) GetStockObject (WHITE_BRUSH));
}/*endCase*/
case WM_CREATE: {
hdc = GetDC (hwnd); // Get the DC for text metrics

GetClientRect (GetParent (hwnd), &rc);
GetTextMetrics (hdc, &tm);

// Calculate the height of the window
lHeight = tm.tmHeight + 10 * GetSystemMetrics (SM_CYBORDER) + 2;

// Save away the calculated height
SetWindowLong (hwnd, GWL_USERDATA, lHeight);

//* resize the window
SetWindowPos (hwnd, NULL, -1, rc.bottom - lHeight,
rc.right + 2, lHeight + 2, SWP_NOZORDER | SWP_NOMOVE);

ReleaseDC (hwnd, hdc);
break;
}/*endCase*/
case WM_USER_UPDATE_STATUS: {
switch (lParam) {
case ID_DDEML_CONNECT: {
SetWindowText (hwndStatusText, "DDEML Connection");
break;
}/*endCase*/
case ID_DDEML_RETRIEVING: {
SetWindowText (hwndStatusText, "DDEML Retrieving");
break;
}/*endCase*/
case ID_DDEML_DISCONNECT: {
SetWindowText (hwndStatusText, "DDEML Disconnect");
break;
}/*endCase*/
case ID_DDEML_COMPLETE: {
SetWindowText (hwndStatusText, "DDEML Complete");
break;
}/*endCase*/
case ID_DDEML_ACTIVATE: {
SetWindowText (hwndStatusText, "DDEML Activate Group");
break;
}/*endCase*/
case ID_DDEML_CREATE: {
SetWindowText (hwndStatusText, "DDEML Create Group");
break;
}/*endCase*/
case ID_DDEML_ADD: {
TCHAR szText[32];

sprintf (szText, "DDEML Add Item %ld", wParam);
SetWindowText (hwndStatusText, szText);
break;
}/*endCase*/
}/*endSwitch*/
break;
}/*endCase*/
case WM_PAINT: {
HBRUSH hBrush;
HBRUSH hBrushTemp;
HPEN hPen;
HPEN hPenTemp;

hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rc);

lHeight = GetWindowLong (hwnd, GWL_USERDATA);
pts[0].x = 3;
pts[0].y = pts[5].y = lHeight - 4;
pts[1].x = 6;
pts[1].y = pts[2].y = lHeight - 6;
pts[2].x = pts[3].x = (rc.right / 2) - 4;
pts[3].y = 6;
pts[4].y = 3;
pts[4].x = pts[5].x = rc.right / 2;
hBrush = GetStockObject (WHITE_BRUSH);
hPen = GetStockObject (WHITE_PEN);
hBrushTemp = SelectObject (hdc, hBrush);
hPenTemp = SelectObject (hdc, hPen);
SetPolyFillMode (hdc, WINDING);
Polygon (hdc, pts, 6);
hBrush = CreateSolidBrush (GetSysColor (COLOR_BTNSHADOW));
pts[2].x = 6;
hPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW));
pts[2].y = 6;
pts[5].x = pts[5].y = 3;
SelectObject (hdc, hBrush);
SelectObject (hdc, hPen);
Polygon (hdc, pts, 6);
rc.left = rc.top = 7;
rc.right = (rc.right / 2) - 4;
rc.bottom = lHeight - 7;
SelectObject (hdc, hBrushTemp);
SelectObject (hdc, hPenTemp);
DeleteObject (hBrush);
DeleteObject (hPen);
hBrush = GetStockObject (WHITE_BRUSH);
FillRect (hdc, &rc, hBrush);
DeleteObject (hBrush);
EndPaint (hwnd, &ps);
return (0L);
}/*endCase*/
}/*endSwitch*/
return (DefWindowProc (hwnd, uiMsg, wParam, lParam));
}/* end StatusBarWndProc */

/********************************************************************

ListBoxWndProc.

Function that manages the list boxes that are on the screen. Subclassed
to provide additional functionality.

********************************************************************/

LRESULT APIENTRY ListBoxWndProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
LRESULT lParam) {

switch (uiMsg) {
case WM_KEYUP: {
SynchronizeLists (hwnd);
break;
}/*endCase*/
case WM_VSCROLL: {
SynchronizeLists (hwnd);
break;
}/*endCase*/
break;
}/*endSwitch*/
return (CallWindowProc (DefListBoxWndProc, hwnd, uiMsg, wParam, lParam));
}/* end ListBoxWndProc */

/********************************************************************

SynchronizeLists.

Function that makes sure that the two lists are synchronized and
always have the same selection.

********************************************************************/

void SynchronizeLists (HWND hwnd) {
HWND hwndOther;
long lSourceTop;
long lTargetTop;

// If this is from the combo list then return.
if (hwnd == hwndCombo) {
return;
}/*endIf*/

// Figure out which list caused the event and update the other.
if (hwnd == hwndFileList) {
hwndOther = hwndFileList2;
} else {
hwndOther = hwndFileList;
}/*endIf*/

// Get the top index of the source list.
lSourceTop = SendMessage (hwnd, LB_GETTOPINDEX, 0, 0L);

// Get the top index of the target list.
lTargetTop = SendMessage (hwndOther, LB_GETTOPINDEX, 0, 0L);

// If the top indexes are different set the top of the target to the
// same value as the source.
if (lSourceTop != lTargetTop) {
SendMessage (hwndOther, LB_SETTOPINDEX, lSourceTop, 0L);
}/*endIf*/
}/* end SynchronizeLists */

/********************************************************************

SynchronizeListSelection.

Function that actually manages the list selection.

********************************************************************/

void SynchronizeListSelection (HWND hwnd) {
HWND hwndOther;
long lNumSel;
int * lpSelection;
long lIndex;

// If this is from the combo list then return.

if (hwnd == hwndCombo) {
return;
}/*endIf*/

// Figure out which list caused the event and update the other.

if (hwnd == hwndFileList) {
hwndOther = hwndFileList2;
} else {
hwndOther = hwndFileList;
}/*endIf*/

// Find out how many items are selected in the source list.

lNumSel = SendMessage (hwnd, LB_GETSELCOUNT, 0, 0L);
if (lNumSel != LB_ERR && lNumSel != 0) {

// Allocate a block of memory to hold the selection indexes.
lpSelection = (int *) GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT,
lNumSel * sizeof (int));
if (lpSelection) {

// Clear the selection in the list before reselecting.
// Under Win 3.x LPARAM of LB_SETSEL is MAKELPARAM (-1, 0)
// Under Win32 it is -1

SendMessage (hwndOther, LB_SETSEL, (WPARAM) FALSE, (LPARAM) -1);

// Retrieve the selection indexes.

SendMessage (hwnd, LB_GETSELITEMS, lNumSel, (LPARAM) lpSelection);

// Loop the indexes selecting the same values in the target list.

for (lIndex = 0; lIndex < lNumSel; lIndex++) {
SendMessage (hwndOther, LB_SETSEL, (WPARAM) TRUE,
MAKELPARAM (lpSelection[lIndex], 0));
}/*endFor*/

// Release the memory that was allocated.

GlobalFree (lpSelection);
}/*endIf*/
}/*endIf*/
}/* end SynchronizeListSelection */

/********************************************************************

CreateChildren.

Function that creates all of the child windows for the app.

********************************************************************/

void CreateChildren (HWND hwnd) {
int iListHeight;
long lHeight;
RECT rc;

// Create the status bar at the bottom of the window.
hwndStatus = CreateWindow ("StatusBar", NULL,
WS_BORDER | SS_LEFT | WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hwnd, (HMENU) ID_STATUSBAR, ghModule, NULL);

// Retrieve the height of the status bar.
lHeight = GetWindowLong (hwndStatus, GWL_USERDATA);

// Retrieve the size of the client area of the status bar.
GetClientRect (hwndStatus, &rc);

hwndStatusText = CreateWindow ("Static", "Status Bar",
WS_VISIBLE | WS_CHILD | SS_LEFT,
7, 7, rc.right / 2 - 10, lHeight - 14, hwndStatus, (HMENU) 0, ghModule,
NULL);

// Retrieve the size of the client area of the parent window
GetClientRect (hwnd, &rc);

// Calculate the size of a list box.
iListHeight = rc.bottom - lHeight * 2;

// Decrease the size of lHeight to compensate for size of status bar.
lHeight -= 8;

// Create a Static window in the upper left corner.
CreateWindow ("Static", "Available exe's",
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | SS_LEFT,
0, 0, 200, lHeight - 2, hwnd, (HMENU) 0, ghModule, NULL);

// Create the first list to hold the file name.
hwndFileList = CreateWindow ("ListBox", NULL, WS_CLIPSIBLINGS | LBS_NOTIFY |
WS_BORDER | WS_VISIBLE | WS_CHILD | LBS_EXTENDEDSEL | LBS_HASSTRINGS,
0, lHeight, 150, iListHeight, hwnd, (HMENU) ID_FILELIST, ghModule,
NULL);

// Subclass the list box window proc so we can do the synchronization
DefListBoxWndProc = (WNDPROC) GetWindowLong (hwndFileList, GWL_WNDPROC);
SetWindowLong (hwndFileList, GWL_WNDPROC, (LONG) ListBoxWndProc);

// Create the second list box that holds the name that will be used in the
// Program Manager.
hwndFileList2 = CreateWindow ("ListBox", NULL,
WS_BORDER | WS_VISIBLE | WS_CHILD | WS_VSCROLL | LBS_EXTENDEDSEL |
LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_CLIPSIBLINGS, 150,
lHeight, 150, iListHeight, hwnd, (HMENU) ID_FILELIST2, ghModule,
NULL);

// Subclass the list.
SetWindowLong (hwndFileList2, GWL_WNDPROC, (LONG) ListBoxWndProc);

// Create a third list box that is not visible that contains the absolute
// path to the executable.
hwndPathList = CreateWindow ("ListBox", NULL,
WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_EXTENDEDSEL |
LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_CLIPSIBLINGS, 150, lHeight,
150, iListHeight, hwnd, (HMENU) ID_PATHLIST, ghModule, NULL);

// Create a button that is used to add a group.
hwndAddGroupButton = CreateWindow ("Button", "Add Group",
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
rc.right - 110, iListHeight - (int) (lHeight * 4),
100, lHeight, hwnd, (HMENU) ID_ADDGROUP, ghModule, NULL);

// Create the button that is used to add the selected items.
hwndAddButton = CreateWindow ("Button", "Add Items",
WS_DISABLED | WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
rc.right - 110, iListHeight - (int) (lHeight * 3),
100, lHeight, hwnd, (HMENU) ID_ADDBUTTON, ghModule, NULL);

// Create the button that is used to select all of the items in the list.
hwndAddAll = CreateWindow ("Button", "Select All",
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
rc.right - 110, iListHeight - (int) (lHeight * 2),
100, lHeight, hwnd, (HMENU) ID_ADDALLBUTTON, ghModule, NULL);

// Create a button that can be used to exit the application.
hwndExitButton = CreateWindow ("Button", "Exit",
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
rc.right - 110, iListHeight - (int) lHeight, 100, lHeight, hwnd,
(HMENU) ID_EXITBUTTON, ghModule, NULL);

// Create a drop down combo box for the group names from the Program Manager.
hwndCombo = CreateWindow ("ComboBox", NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | CBS_DROPDOWN | WS_VSCROLL |
CBS_AUTOHSCROLL | CBS_HASSTRINGS, rc.right - 200, lHeight,
190, lHeight * 5, hwnd, (HMENU) ID_COMBOBOX, ghModule, NULL);

// Create a Static window to label the combo box.
CreateWindow ("Static", "Available Groups",
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | SS_LEFT,
rc.right - 200, 0, 190, lHeight - 2, hwnd, (HMENU) 0, ghModule, NULL);
}/* end CreateChildren */