You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2916 lines
80 KiB
2916 lines
80 KiB
|
|
/*****************************************************************************
|
|
|
|
C L I P B O O K U T I L I T I E S
|
|
|
|
Name: cvutil.c
|
|
Date: 21-Jan-1994
|
|
Creator: Unknown
|
|
|
|
Description:
|
|
Utility functions for clipbook viewer.
|
|
|
|
|
|
*****************************************************************************/
|
|
|
|
#define WIN31
|
|
#define STRICT
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <commctrl.h>
|
|
#include <assert.h>
|
|
#include <memory.h>
|
|
#include <stdio.h>
|
|
#include <strsafe.h>
|
|
|
|
#include "common.h"
|
|
#include "clipbook.h"
|
|
#include "clipbrd.h"
|
|
#include "clipdsp.h"
|
|
#include "cvinit.h"
|
|
#include "cvutil.h"
|
|
#include "dib.h"
|
|
#include "strtok.h"
|
|
#include "initmenu.h"
|
|
#include "debugout.h"
|
|
|
|
|
|
DWORD gXERR_Type = 0;
|
|
DWORD gXERR_Err = 0;
|
|
HSZ hszErrorRequest = 0;
|
|
|
|
|
|
#if DEBUG
|
|
static void DumpDataReq (PDATAREQ pdr);
|
|
|
|
|
|
static void DumpDataReq(
|
|
PDATAREQ pdr)
|
|
{
|
|
PINFO(TEXT("Datareq: type %d, to window %lx, \r\nat index %u, fDisc=%u, format=%u\r\n"),
|
|
pdr->rqType,
|
|
pdr->hwndMDI,
|
|
pdr->iListbox,
|
|
pdr->fDisconnect,
|
|
pdr->wFmt);
|
|
}
|
|
#else
|
|
#define DumpDataReq(x)
|
|
#endif
|
|
|
|
|
|
|
|
// AdjustControlSizes //////////////////
|
|
//
|
|
// This function sizes the listbox windows associated
|
|
// with an MDI child window when its size changes
|
|
|
|
VOID AdjustControlSizes (
|
|
HWND hwnd)
|
|
{
|
|
RECT rc1, rc2;
|
|
PMDIINFO pMDI;
|
|
int cx = GetSystemMetrics ( SM_CXVSCROLL );
|
|
int cy = GetSystemMetrics ( SM_CYHSCROLL );
|
|
|
|
|
|
if (!(pMDI = GETMDIINFO(hwnd)))
|
|
return;
|
|
|
|
|
|
GetClientRect ( hwnd, &rc1 );
|
|
rc2 = rc1;
|
|
rc2.right -= cx - 1;
|
|
rc2.bottom -= cy - 1;
|
|
|
|
switch ( pMDI->DisplayMode )
|
|
{
|
|
case DSP_LIST:
|
|
case DSP_PREV:
|
|
MoveWindow ( pMDI->hWndListbox, rc1.left - 1, rc1.top - 1,
|
|
rc1.right - rc1.left + 2, ( rc1.bottom - rc1.top ) + 2, TRUE );
|
|
break;
|
|
|
|
case DSP_PAGE:
|
|
MoveWindow (pMDI->hwndHscroll,
|
|
rc1.left - 1,
|
|
rc2.bottom,
|
|
(rc2.right - rc2.left) +2,
|
|
cy,
|
|
TRUE );
|
|
|
|
if ( pMDI->flags & F_CLPBRD ) {
|
|
MoveWindow ( pMDI->hwndVscroll, rc2.right, rc1.top - 1,
|
|
cx, ( rc2.bottom - rc2.top ) + 2, TRUE );
|
|
}
|
|
else
|
|
{
|
|
MoveWindow ( pMDI->hwndVscroll, rc2.right, rc1.top - 1,
|
|
cx, ( rc2.bottom - rc2.top ) + 2 - 2*cy, TRUE );
|
|
}
|
|
MoveWindow ( pMDI->hwndSizeBox, rc2.right, rc2.bottom, cx, cy, TRUE );
|
|
|
|
if ( ! ( pMDI->flags & F_CLPBRD ) )
|
|
{
|
|
MoveWindow ( pMDI->hwndPgUp, rc2.right,
|
|
rc2.bottom + 1 - 2*cy, cx, cy, TRUE );
|
|
MoveWindow ( pMDI->hwndPgDown, rc2.right,
|
|
rc2.bottom + 1 - cy, cx, cy, TRUE );
|
|
}
|
|
|
|
// adjust display window
|
|
pMDI->rcWindow = rc2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID ShowHideControls (
|
|
HWND hwnd)
|
|
{
|
|
PMDIINFO pMDI;
|
|
int nShowScroll;
|
|
int nShowList;
|
|
|
|
|
|
if (!(pMDI = GETMDIINFO(hwnd)))
|
|
return;
|
|
|
|
|
|
switch ( pMDI->DisplayMode )
|
|
{
|
|
case DSP_PREV:
|
|
case DSP_LIST:
|
|
nShowScroll = SW_HIDE;
|
|
nShowList = SW_SHOW;
|
|
break;
|
|
|
|
case DSP_PAGE:
|
|
if ( GetBestFormat( hwnd, pMDI->CurSelFormat) != CF_OWNERDISPLAY )
|
|
nShowScroll = SW_SHOW;
|
|
else
|
|
{
|
|
nShowScroll = SW_HIDE;
|
|
ShowScrollBar ( hwnd, SB_BOTH, TRUE );
|
|
}
|
|
nShowList = SW_HIDE;
|
|
break;
|
|
}
|
|
|
|
ShowWindow ( pMDI->hWndListbox, nShowList );
|
|
ShowWindow ( pMDI->hwndVscroll, nShowScroll );
|
|
ShowWindow ( pMDI->hwndHscroll, nShowScroll );
|
|
ShowWindow ( pMDI->hwndSizeBox, nShowScroll );
|
|
ShowWindow ( pMDI->hwndPgUp, (pMDI->flags & F_CLPBRD)? SW_HIDE: nShowScroll );
|
|
ShowWindow ( pMDI->hwndPgDown, (pMDI->flags & F_CLPBRD)? SW_HIDE: nShowScroll );
|
|
}
|
|
|
|
|
|
|
|
// AssertConnection /////////////////
|
|
|
|
BOOL AssertConnection (
|
|
HWND hwnd)
|
|
{
|
|
PMDIINFO pMDI;
|
|
|
|
if (!(pMDI = GETMDIINFO(hwnd)))
|
|
return FALSE;
|
|
|
|
if (IsWindow(hwnd))
|
|
{
|
|
if (pMDI->hExeConv ||
|
|
(pMDI->hExeConv = InitSysConv (hwnd,
|
|
pMDI->hszConvPartner,
|
|
hszClpBookShare,
|
|
FALSE))
|
|
)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// InitSysConv ////////////////////////
|
|
//
|
|
// Purpose: Establishes a conversation with the given app and topic.
|
|
//
|
|
// Parameters:
|
|
// hwnd - MDI child window to own this conversation
|
|
// hszApp - App name to connect to
|
|
// hszTopic - Topic to connect to
|
|
// fLocal - Ignored.
|
|
//
|
|
// Returns: Handle to the conversation (0L if no conv. could be established).
|
|
//
|
|
|
|
HCONV InitSysConv (
|
|
HWND hwnd,
|
|
HSZ hszApp,
|
|
HSZ hszTopic,
|
|
BOOL fLocal )
|
|
{
|
|
HCONV hConv = 0L;
|
|
PDATAREQ pDataReq;
|
|
DWORD dwErr;
|
|
|
|
|
|
#if DEBUG
|
|
TCHAR atchApp[256];
|
|
TCHAR atchTopic[256];
|
|
|
|
if (DdeQueryString(idInst, hszApp, atchApp,
|
|
sizeof(atchApp), CP_WINANSI) &&
|
|
DdeQueryString(idInst, hszTopic, atchTopic,
|
|
sizeof(atchTopic), CP_WINANSI))
|
|
{
|
|
PINFO(TEXT("InitSysConv: [%s | %s]\r\n"), atchApp, atchTopic);
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("I don't know my app/topic pair!\r\n"));
|
|
}
|
|
#endif
|
|
|
|
|
|
if (LockApp (TRUE, szEstablishingConn))
|
|
{
|
|
hConv = DdeConnect ( idInst, hszApp, hszTopic, NULL );
|
|
if (!hConv)
|
|
{
|
|
dwErr = DdeGetLastError(idInst);
|
|
PINFO(TEXT("Failed first try at CLIPSRV, #%x\r\n"), dwErr);
|
|
|
|
if (GetSystemMetrics(SM_REMOTESESSION) )
|
|
{
|
|
MessageBoxID (hInst, hwnd, IDS_TSNOTSUPPORTED, IDS_APPNAME, MB_OK | MB_ICONHAND);
|
|
}
|
|
else
|
|
{
|
|
MessageBoxID (hInst, hwnd, IDS_NOCLPBOOK, IDS_APPNAME, MB_OK | MB_ICONHAND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PINFO(TEXT("Making datareq."));
|
|
|
|
if ( pDataReq = CreateNewDataReq() )
|
|
{
|
|
pDataReq->rqType = RQ_EXECONV;
|
|
pDataReq->hwndMDI = hwnd;
|
|
pDataReq->wFmt = CF_TEXT;
|
|
DdeSetUserHandle ( hConv, (DWORD)QID_SYNC, (DWORD_PTR)pDataReq );
|
|
|
|
Sleep(3000);
|
|
PINFO(TEXT("Entering AdvStart transaction "));
|
|
|
|
if (!MySyncXact ( NULL, 0L, hConv, hszTopics,
|
|
CF_TEXT, XTYP_ADVSTART, LONG_SYNC_TIMEOUT, NULL ))
|
|
{
|
|
XactMessageBox (hInst, hwnd, IDS_APPNAME, MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("InitSysConv:Could not create data req\r\n"));
|
|
}
|
|
}
|
|
LockApp ( FALSE, szNull );
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("app locked in initsysconv\n\r"));
|
|
}
|
|
|
|
return hConv;
|
|
}
|
|
|
|
|
|
|
|
// UpdateListBox ////////////////////////////
|
|
//
|
|
// This function updates the contents of a listbox
|
|
// given the window handle of the MDI child window
|
|
// and the conversation over which the data is to be
|
|
// obtained
|
|
|
|
BOOL UpdateListBox(
|
|
HWND hwnd,
|
|
HCONV hConv)
|
|
{
|
|
HDDEDATA hData;
|
|
BOOL fOK = TRUE;
|
|
|
|
|
|
if ( hConv == 0L || !IsWindow( hwnd ))
|
|
{
|
|
PERROR(TEXT("UpdateListBox called with garbage\n\r"));
|
|
fOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (GETMDIINFO(hwnd) && GETMDIINFO(hwnd)->flags & F_LOCAL)
|
|
{
|
|
PINFO(TEXT("Getting all topics\r\n"));
|
|
}
|
|
else
|
|
{
|
|
PINFO(TEXT("Getting shared topics\r\n"));
|
|
}
|
|
|
|
|
|
// ask clipsrv to initialize shares
|
|
|
|
MySyncXact (SZCMD_INITSHARE,
|
|
sizeof (SZCMD_INITSHARE),
|
|
hConv,
|
|
0L,
|
|
CF_TEXT,
|
|
XTYP_EXECUTE,
|
|
SHORT_SYNC_TIMEOUT,
|
|
NULL);
|
|
|
|
|
|
//get the data
|
|
|
|
hData = MySyncXact (NULL,
|
|
0L,
|
|
hConv,
|
|
hszTopics,
|
|
CF_TEXT,
|
|
XTYP_REQUEST,
|
|
SHORT_SYNC_TIMEOUT,
|
|
NULL );
|
|
|
|
if ( !hData )
|
|
{
|
|
XactMessageBox (hInst,
|
|
hwnd,
|
|
IDS_APPNAME,
|
|
MB_OK | MB_ICONEXCLAMATION);
|
|
fOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
fOK = InitListBox ( hwnd, hData );
|
|
}
|
|
}
|
|
|
|
return fOK;
|
|
}
|
|
|
|
|
|
|
|
// GetPreviewBitmap //////////////////////////////
|
|
// Informs CLIPSRV via DDE that we need a preview bitmap
|
|
// for the given page.
|
|
//
|
|
// Parameters:
|
|
// hwnd - Clipbook window which wants the bitmap
|
|
// szName - Name of the clipbook page.
|
|
// index - Page's index within the listbox in hwnd
|
|
//
|
|
// Returns:
|
|
// void.
|
|
//
|
|
|
|
BOOL GetPreviewBitmap (
|
|
HWND hwnd,
|
|
LPTSTR szName,
|
|
UINT index)
|
|
{
|
|
HSZ hszTopic, hszItem = 0L;
|
|
HCONV hConv;
|
|
HDDEDATA hRet;
|
|
PDATAREQ pDataReq;
|
|
BOOL fLocked;
|
|
TCHAR tchTmp;
|
|
|
|
|
|
if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
|
|
return FALSE;
|
|
|
|
fLocked = LockApp (TRUE, NULL);
|
|
|
|
|
|
tchTmp = szName[0];
|
|
szName[0] = SHR_CHAR;
|
|
|
|
if (0 == (hszTopic = DdeCreateStringHandle (idInst, szName, 0)))
|
|
{
|
|
PERROR(TEXT("GetPreviewBitmap: no topic handle\n\r"));
|
|
goto done;
|
|
}
|
|
|
|
if (0 == (hszItem = DdeCreateStringHandle (idInst, SZPREVNAME, 0)))
|
|
{
|
|
PERROR(TEXT("GetPreviewBitmap: no item handle\n\r"));
|
|
goto done;
|
|
}
|
|
|
|
if (!GETMDIINFO(hwnd))
|
|
{
|
|
PERROR(TEXT("GETMDIINFO(hwnd) -> NULL\n\r"));
|
|
goto done;
|
|
}
|
|
|
|
if (NULL == (pDataReq = CreateNewDataReq()))
|
|
{
|
|
PERROR(TEXT("GetPreviewBitmap: no pdatareq\n\r"));
|
|
goto done;
|
|
}
|
|
|
|
#if DEBUG
|
|
{
|
|
TCHAR atch[64];
|
|
|
|
DdeQueryString(idInst, GETMDIINFO(hwnd)->hszConvPartnerNP,
|
|
atch, 64, CP_WINANSI);
|
|
PINFO(TEXT("GetPrevBmp: Connecting [%s | %s ! %s]\r\n"),
|
|
atch, szName, SZPREVNAME);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// Let's try to connect up to ten times. Sometimes when updating
|
|
// the thumbnails if the user changes a page, the server will be
|
|
// busy doing that and we can't connect here. So, at least try
|
|
// a few times.
|
|
//
|
|
{
|
|
INT trycnt = 0;
|
|
hConv = 0L;
|
|
|
|
while (trycnt < 10 && !hConv)
|
|
{
|
|
hConv = DdeConnect (idInst, GETMDIINFO(hwnd)->hszConvPartnerNP, hszTopic, NULL);
|
|
trycnt++;
|
|
if (hConv) continue;
|
|
|
|
PINFO (TEXT("GetPreviewBitmap: trying to connect again\r\n"));
|
|
Sleep (200);
|
|
}
|
|
}
|
|
|
|
|
|
if (hConv)
|
|
{
|
|
DWORD adwTrust[3];
|
|
BOOL fLocal = FALSE;
|
|
|
|
if (GETMDIINFO(hwnd)->flags & F_LOCAL)
|
|
{
|
|
fLocal = TRUE;
|
|
|
|
if (NDDE_NO_ERROR != NDdeGetTrustedShare(NULL, szName,
|
|
adwTrust, adwTrust + 1, adwTrust + 2))
|
|
{
|
|
adwTrust[0] = 0L;
|
|
}
|
|
|
|
NDdeSetTrustedShare (NULL,
|
|
szName,
|
|
adwTrust[0] | NDDE_TRUST_SHARE_INIT);
|
|
}
|
|
|
|
pDataReq->rqType = RQ_PREVBITMAP;
|
|
pDataReq->hwndList = GETMDIINFO(hwnd)->hWndListbox;
|
|
pDataReq->iListbox = index;
|
|
pDataReq->hwndMDI = hwnd;
|
|
pDataReq->fDisconnect = TRUE;
|
|
pDataReq->wFmt = (WORD)cf_preview;
|
|
pDataReq->wRetryCnt = 3;
|
|
|
|
|
|
{
|
|
/**** disable all edit function ****/
|
|
/**** will enable in after callback ****/
|
|
|
|
// If the user does a paste or make some changes to the pages while
|
|
// clipbrd is waiting for the xaction to complete, sometimes we get
|
|
// a popup says there's a problem with connection (or something similar)
|
|
// It seems there's some dirty code is causing this. Below is a temp
|
|
// fix which works well on fast machines. On slower machines it may
|
|
// still fail at times. A better fix may be not to use async at all.
|
|
//
|
|
// NOTE: If there's multiple requests, one may complete while we're still
|
|
// waitng for another. This will cause the EDIT functions to be enabled
|
|
// while we are still waiting.
|
|
|
|
HANDLE hmenu;
|
|
|
|
hmenu = GetMenu (hwndApp);
|
|
|
|
EnableMenuItem (hmenu, IDM_COPY, MF_GRAYED | MF_BYCOMMAND);
|
|
EnableMenuItem (hmenu, IDM_KEEP, MF_GRAYED | MF_BYCOMMAND);
|
|
EnableMenuItem (hmenu, IDM_PASTE_PAGE, MF_GRAYED | MF_BYCOMMAND);
|
|
EnableMenuItem (hmenu, IDM_DELETE, MF_GRAYED | MF_BYCOMMAND);
|
|
|
|
SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_COPY, FALSE);
|
|
SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_KEEP, FALSE);
|
|
SendMessage (hwndToolbar, TB_ENABLEBUTTON, IDM_DELETE, FALSE);
|
|
}
|
|
|
|
hRet = DdeClientTransaction (NULL,
|
|
0L,
|
|
hConv,
|
|
hszItem,
|
|
cf_preview,
|
|
XTYP_REQUEST,
|
|
(DWORD)TIMEOUT_ASYNC,
|
|
NULL);
|
|
|
|
if ( !hRet )
|
|
{
|
|
unsigned uiErr;
|
|
|
|
uiErr = DdeGetLastError (idInst);
|
|
PERROR(TEXT("GetPreviewBitmap: Async Transaction for (%s) failed:%x\n\r"),
|
|
szName, uiErr);
|
|
}
|
|
|
|
DdeSetUserHandle ( hConv, (DWORD)QID_SYNC, (DWORD_PTR)pDataReq );
|
|
}
|
|
#if DEBUG
|
|
else
|
|
{
|
|
unsigned uiErr;
|
|
|
|
uiErr = DdeGetLastError(idInst);
|
|
DdeQueryString(idInst, GETMDIINFO(hwnd)->hszConvPartner,
|
|
szBuf, 128, CP_WINANSI );
|
|
PERROR(TEXT("GetPreviewBitmap: connect to %lx|%lx (%s|%s) failed: %d\n\r"),
|
|
GETMDIINFO(hwnd)->hszConvPartner, hszTopic,
|
|
(LPTSTR)szBuf, (LPTSTR)szName, uiErr);
|
|
}
|
|
#endif
|
|
|
|
|
|
done:
|
|
|
|
if (!hszTopic)
|
|
DdeFreeStringHandle (idInst, hszTopic);
|
|
|
|
if (!hszItem)
|
|
DdeFreeStringHandle ( idInst, hszItem );
|
|
|
|
if (fLocked)
|
|
LockApp (FALSE, NULL);
|
|
|
|
szName[0] = tchTmp;
|
|
|
|
SetEvent (hXacting);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID SetBitmapToListboxEntry (
|
|
HDDEDATA hbmp,
|
|
HWND hwndList,
|
|
UINT index)
|
|
{
|
|
LPLISTENTRY lpLE;
|
|
RECT rc;
|
|
HBITMAP hBitmap;
|
|
LPBYTE lpBitData;
|
|
DWORD cbDataLen;
|
|
unsigned uiErr;
|
|
|
|
|
|
#if DEBUG
|
|
uiErr = DdeGetLastError(idInst);
|
|
if (uiErr)
|
|
{
|
|
PINFO(TEXT("SBmp2LBEntr: %d\r\n"), uiErr);
|
|
}
|
|
#endif
|
|
|
|
|
|
if (!IsWindow (hwndList)
|
|
|| SendMessage (hwndList, LB_GETTEXT, index, (LPARAM)(LPCSTR)&lpLE) == LB_ERR
|
|
|| SendMessage (hwndList, LB_GETITEMRECT, index, (LPARAM)(LPRECT)&rc) == LB_ERR)
|
|
{
|
|
DdeFreeDataHandle(hbmp);
|
|
PERROR(TEXT("SetBitmapToListboxEntry: bad window: %x\n\r"), hwndList);
|
|
}
|
|
else
|
|
{
|
|
if (hbmp)
|
|
{
|
|
if ( lpBitData = DdeAccessData ( hbmp, &cbDataLen ))
|
|
{
|
|
// create the preview bitmap
|
|
hBitmap = CreateBitmap (PREVBMPSIZ,PREVBMPSIZ,1,1, lpBitData);
|
|
DdeUnaccessData ( hbmp );
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("SB2LB: Couldn't access data!\r\n"));
|
|
hBitmap = NULL;
|
|
}
|
|
|
|
DdeFreeDataHandle ( hbmp );
|
|
lpLE->hbmp = hBitmap;
|
|
|
|
PINFO(TEXT("Successfully set bmp.\r\n"));
|
|
}
|
|
|
|
PINFO(TEXT("Invalidating (%d,%d)-(%d,%d)\r\n"),rc.left, rc.top,
|
|
rc.right, rc.bottom);
|
|
InvalidateRect ( hwndList, &rc, TRUE );
|
|
}
|
|
|
|
|
|
uiErr = DdeGetLastError(idInst);
|
|
if (uiErr)
|
|
{
|
|
PINFO (TEXT("SBmp2LBEntr: exit err %d\r\n"), uiErr);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* UpdatePage
|
|
*
|
|
* When user paste into an existing page, the first item
|
|
* in szList is the share name of the page pasted. Since
|
|
* the name did not change, we need to do some special
|
|
* processing to update the display.
|
|
*
|
|
*/
|
|
|
|
BOOL UpdatePage (HWND hwnd, LPTSTR szList)
|
|
{
|
|
PMDIINFO pMDI;
|
|
PLISTENTRY pLE;
|
|
TCHAR szPageBuf[MAX_NDDESHARENAME+1];
|
|
LPTSTR szPage = szPageBuf;
|
|
RECT Rect;
|
|
INT i;
|
|
|
|
|
|
*szPage = TEXT('\0');
|
|
|
|
// does the first item in szList spcifies
|
|
// an updated page?
|
|
|
|
if (BOGUS_CHAR != *szList)
|
|
return FALSE;
|
|
|
|
|
|
// get the share name
|
|
|
|
szList++;
|
|
|
|
while (*szList && TEXT('\t') != *szList)
|
|
*szPage++ = *szList++;
|
|
|
|
*szPage = TEXT('\0');
|
|
|
|
|
|
// Find the page, notice the name comparison below does not
|
|
// compare the first char. This is because the updated page's
|
|
// share state may have changed so the first char won't match.
|
|
|
|
pMDI = GETMDIINFO(hwnd);
|
|
|
|
for (i=0;
|
|
LB_ERR != SendMessage(pMDI->hWndListbox, LB_GETTEXT, i, (LPARAM)&pLE);
|
|
i++)
|
|
{
|
|
if (pLE)
|
|
if (!lstrcmpiA(pLE->name+1, szPageBuf+1))
|
|
{
|
|
goto update;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
update:
|
|
|
|
// invalidate the preview bitmap
|
|
|
|
SendMessage (pMDI->hWndListbox, LB_GETITEMRECT, i, (LPARAM)&Rect);
|
|
|
|
if (pLE->hbmp)
|
|
DeleteObject (pLE->hbmp);
|
|
|
|
pLE->fTriedGettingPreview = FALSE;
|
|
pLE->hbmp = NULL;
|
|
|
|
InvalidateRect (pMDI->hWndListbox, &Rect, FALSE);
|
|
|
|
|
|
// if in page view and the page is the one currently
|
|
// selected then update the page view
|
|
|
|
if (DSP_PAGE == pMDI->DisplayMode)
|
|
if (SendMessage (pMDI->hWndListbox, LB_GETCURSEL, 0, 0) == i)
|
|
PostMessage (hwndApp, WM_COMMAND, IDM_UPDATE_PAGEVIEW, 0L);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// InitListBox //////////////////////////////////
|
|
//
|
|
// this function initializes the entries of a listbox
|
|
// given the handle of the MDI child window that owns
|
|
// the list box and a ddeml data handle that contains the
|
|
// tab-separated list of items that are to appear in the
|
|
// listbox
|
|
// Right now, this deletes all entries in the list and
|
|
// then recreates them. It would be more efficient to add or
|
|
// delete only those items that have changed. This would save
|
|
// CONSIDERABLE time in thumbnail mode-- now, we have to
|
|
// establish a new DDE conversation with the server for each
|
|
// page, just to get the thumbnail bitmap.
|
|
|
|
|
|
BOOL InitListBox (
|
|
HWND hwnd,
|
|
HDDEDATA hData )
|
|
{
|
|
PMDIINFO pMDI;
|
|
PLISTENTRY pLE;
|
|
LPTSTR lpszList, q;
|
|
DWORD cbDataLen;
|
|
HWND hwndlist;
|
|
int OldCount;
|
|
int NewCount;
|
|
int OldSel;
|
|
LPTSTR OldSelString;
|
|
BOOL OldStringDeleted;
|
|
int i;
|
|
BOOL fDel;
|
|
|
|
|
|
if ( hData == 0L || !IsWindow ( hwnd ) )
|
|
{
|
|
PERROR(TEXT("InitListBox called with garbage\n\r"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Get a copy of the data in the handle
|
|
lpszList = (LPTSTR)DdeAccessData ( hData, &cbDataLen );
|
|
DdeUnaccessData(hData);
|
|
lpszList = GlobalAllocPtr(GHND, cbDataLen);
|
|
DdeGetData(hData, lpszList, cbDataLen, 0L);
|
|
|
|
// Sometimes, the data will be longer than the string. This
|
|
// would make the 'put tabs back' code below fail if we didn't
|
|
// do this.
|
|
cbDataLen = lstrlen(lpszList);
|
|
|
|
PINFO(TEXT("InitLB: %s \r\n"), lpszList);
|
|
|
|
if (!lpszList)
|
|
{
|
|
PERROR(TEXT("error accessing data in InitListBox\n\r"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!(pMDI = GETMDIINFO(hwnd)))
|
|
return FALSE;
|
|
|
|
|
|
if (!(hwndlist = GETMDIINFO(hwnd)->hWndListbox))
|
|
return FALSE;
|
|
|
|
|
|
SendMessage ( hwndlist, WM_SETREDRAW, 0, 0L );
|
|
|
|
|
|
// let's update the page that was pasted into
|
|
// an existing page.
|
|
|
|
UpdatePage (hwnd, lpszList);
|
|
|
|
|
|
OldCount = (int)SendMessage ( hwndlist, LB_GETCOUNT, 0, 0L );
|
|
OldSel = (int)SendMessage ( hwndlist, LB_GETCURSEL, 0, 0L );
|
|
OldSelString = (LPTSTR)SendMessage (hwndlist, LB_GETITEMDATA, OldSel, 0);
|
|
OldStringDeleted = FALSE;
|
|
|
|
|
|
// Delete items in list that don't exist anymore
|
|
for (i = 0; i < OldCount; i++)
|
|
{
|
|
SendMessage (hwndlist, LB_GETTEXT, i, (LPARAM)&pLE);
|
|
fDel = TRUE;
|
|
|
|
if (pLE)
|
|
{
|
|
for (q = strtokA(lpszList, "\t"); q; q = strtokA(NULL, "\t"))
|
|
{
|
|
PINFO(TEXT("<%hs>"), q);
|
|
|
|
if (0 == lstrcmpA(pLE->name, q))
|
|
{
|
|
fDel = FALSE;
|
|
*q = BOGUS_CHAR;
|
|
break;
|
|
}
|
|
}
|
|
PINFO(TEXT("\r\n"));
|
|
|
|
// Put back the tab chars that strtok ripped out
|
|
for (q = lpszList;q < lpszList + cbDataLen;q++)
|
|
{
|
|
if ('\0' == *q)
|
|
{
|
|
*q = '\t';
|
|
}
|
|
}
|
|
*q = '\0';
|
|
PINFO(TEXT("Restored %hs\r\n"), lpszList);
|
|
|
|
if (fDel)
|
|
{
|
|
PINFO(TEXT("Deleting item %s at pos %d\r\n"), pLE->name, i);
|
|
pLE->fDelete = TRUE;
|
|
if (OldSelString == (LPTSTR)pLE)
|
|
{
|
|
OldStringDeleted = TRUE;
|
|
}
|
|
SendMessage(hwndlist, LB_DELETESTRING, i, 0L);
|
|
i--;
|
|
if (OldCount)
|
|
{
|
|
OldCount--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("Got NULL pLE!\r\n"));
|
|
}
|
|
}
|
|
|
|
|
|
// Add new items to list
|
|
for (q = strtokA(lpszList, "\t"); q; q = strtokA(NULL, "\t"))
|
|
{
|
|
// only add shared items if remote, never re-add existing items
|
|
if (BOGUS_CHAR != *q &&
|
|
(( GETMDIINFO(hwnd)->flags & F_LOCAL ) || *q == SHR_CHAR ))
|
|
{
|
|
// allocate a new list entry...
|
|
if ( ( pLE = (PLISTENTRY)GlobalAllocPtr ( GHND,
|
|
sizeof ( LISTENTRY ))) != NULL )
|
|
{
|
|
// mark this item to be deleted in WM_DELETEITEM
|
|
pLE->fDelete = TRUE;
|
|
pLE->fTriedGettingPreview = FALSE;
|
|
|
|
StringCchCopy(pLE->name, MAX_PAGENAME_LENGTH + 1, q);
|
|
PINFO(TEXT("Adding item %s\r\n"), pLE->name);
|
|
SendMessage(hwndlist, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)pLE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Select the item at the same position we were at
|
|
|
|
NewCount = (int)SendMessage (hwndlist, LB_GETCOUNT, 0, 0L);
|
|
|
|
if (NewCount)
|
|
if (OldCount == NewCount)
|
|
{
|
|
SendMessage (hwndlist,
|
|
LB_SETCURSEL,
|
|
OldSel,
|
|
0L);
|
|
}
|
|
else if ( (LB_ERR != (LRESULT)OldSelString) && (!OldStringDeleted) )
|
|
{
|
|
SendMessage (hwndlist,
|
|
LB_SELECTSTRING,
|
|
OldSel-1, // listbox is sorted
|
|
(LPARAM)OldSelString);
|
|
}
|
|
|
|
|
|
SendMessage ( hwndlist, WM_SETREDRAW, 1, 0L );
|
|
UpdateNofMStatus( hwnd );
|
|
|
|
|
|
if (lpszList)
|
|
GlobalFreePtr(lpszList);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
// MyGetFormat ////////////////////////////
|
|
//
|
|
// this function returns the UINT ID of the
|
|
// format matching the supplied string. This
|
|
// is the reverse of the "getclipboardformatname" function.
|
|
//
|
|
// Note that the formats &Bitmap, &Picture and Pal&ette exist
|
|
// both as predefined windows clipboard formats and as privately
|
|
// registered formats. The integer switch passed to this function
|
|
// determines whether the instrinsic format or the privately registered
|
|
// format ID is returned
|
|
//
|
|
// GETFORMAT_DONTLIE return instrinsic format i.e. CF_BITMAP
|
|
// GETFORMAT_LIE return registered format i.e. cf_bitmap
|
|
|
|
UINT MyGetFormat(
|
|
LPTSTR szFmt,
|
|
int mode)
|
|
{
|
|
TCHAR szBuff[40];
|
|
unsigned i;
|
|
UINT uiPrivates[] = {CF_BITMAP,
|
|
CF_METAFILEPICT,
|
|
CF_PALETTE,
|
|
CF_ENHMETAFILE,
|
|
CF_DIB};
|
|
|
|
|
|
|
|
PINFO("\nMyGetFormat [%s] %d:", szFmt, mode);
|
|
|
|
for (i = 0; i <= CF_ENHMETAFILE; i++)
|
|
{
|
|
LoadString(hInst, i, szBuff, 40);
|
|
if (!lstrcmp( szFmt, szBuff))
|
|
{
|
|
if (GETFORMAT_DONTLIE == mode)
|
|
{
|
|
PINFO(TEXT("No-lie fmt %d\r\n"), i);
|
|
}
|
|
else
|
|
{
|
|
unsigned j;
|
|
|
|
for (j = 0;j <sizeof(uiPrivates)/sizeof(uiPrivates[0]);j++)
|
|
{
|
|
if (i == uiPrivates[j])
|
|
{
|
|
i = RegisterClipboardFormat(szBuff);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
PINFO(TEXT("Format result %d\r\n"), i);
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
for (i = CF_OWNERDISPLAY;i <= CF_DSPENHMETAFILE ;i++ )
|
|
{
|
|
LoadString(hInst, i, szBuff, 40);
|
|
if (!lstrcmp( szFmt, szBuff))
|
|
{
|
|
if (GETFORMAT_DONTLIE != mode)
|
|
{
|
|
i = RegisterClipboardFormat(szBuff);
|
|
}
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
PINFO(TEXT("Registering format %s\n\r"), szFmt );
|
|
|
|
return RegisterClipboardFormat ( szFmt );
|
|
}
|
|
|
|
|
|
|
|
|
|
// HandleOwnerDraw ////////////////////////////////
|
|
//
|
|
// This function handles drawing of owner draw buttons
|
|
// and listboxes in this app.
|
|
|
|
VOID HandleOwnerDraw(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
LPDRAWITEMSTRUCT lpds;
|
|
RECT tmprc;
|
|
COLORREF OldTextColor;
|
|
COLORREF OldBkColor;
|
|
COLORREF BackColor;
|
|
COLORREF TextColor;
|
|
HBRUSH hBkBrush;
|
|
DWORD cbData = 0L;
|
|
LPLISTENTRY lpLE;
|
|
BOOL fSel = FALSE;
|
|
|
|
|
|
|
|
lpds = (LPDRAWITEMSTRUCT) lParam;
|
|
|
|
// this section handles listbox drawing
|
|
|
|
switch ( lpds->CtlID )
|
|
{
|
|
case ID_LISTBOX:
|
|
if (!GETMDIINFO(hwnd))
|
|
break;
|
|
|
|
if ( GETMDIINFO(hwnd)->DisplayMode == DSP_LIST )
|
|
{
|
|
if ( lpds->itemAction & (ODA_DRAWENTIRE|ODA_SELECT|ODA_FOCUS))
|
|
{
|
|
if ( SendMessage ( GETMDIINFO(hwnd)->hWndListbox, LB_GETTEXT,
|
|
lpds->itemID, (LPARAM)(LPCSTR)&lpLE ) == LB_ERR )
|
|
{
|
|
return;
|
|
}
|
|
|
|
hOldBitmap = SelectObject ( hBtnDC, hbmStatus );
|
|
|
|
tmprc = lpds->rcItem;
|
|
|
|
if ( lpds->itemState & ODS_SELECTED &&
|
|
lpds->itemState & ODS_FOCUS )
|
|
{
|
|
TextColor = GetSysColor ( COLOR_HIGHLIGHTTEXT );
|
|
BackColor = GetSysColor ( COLOR_HIGHLIGHT );
|
|
}
|
|
else
|
|
{
|
|
TextColor = GetSysColor ( COLOR_WINDOWTEXT );
|
|
BackColor = GetSysColor ( COLOR_WINDOW );
|
|
}
|
|
|
|
OldTextColor = SetTextColor ( lpds->hDC, TextColor );
|
|
OldBkColor = SetBkColor ( lpds->hDC, BackColor );
|
|
|
|
hBkBrush = CreateSolidBrush ( BackColor );
|
|
if ( hBkBrush )
|
|
FillRect ( lpds->hDC, &tmprc, hBkBrush );
|
|
DeleteObject ( hBkBrush );
|
|
|
|
hOldFont = SelectObject ( lpds->hDC, hFontPreview );
|
|
|
|
|
|
TextOut (lpds->hDC,
|
|
lpds->rcItem.left + 2 * LSTBTDX,
|
|
lpds->rcItem.top+1,
|
|
&(lpLE->name[1]),
|
|
lstrlen((lpLE->name)) - 1);
|
|
|
|
SelectObject ( lpds->hDC, hOldFont );
|
|
|
|
if ( IsShared( lpLE ) && fShareEnabled )
|
|
{
|
|
BitBlt ( lpds->hDC, lpds->rcItem.left + ( LSTBTDX / 2 ),
|
|
lpds->rcItem.top, LSTBTDX, LSTBTDY,
|
|
hBtnDC,
|
|
SHR_PICT_X,
|
|
SHR_PICT_Y +
|
|
(( lpds->itemState & ODS_SELECTED ) &&
|
|
( lpds->itemState & ODS_FOCUS ) ? 0 : LSTBTDY ),
|
|
SRCCOPY );
|
|
}
|
|
else
|
|
{
|
|
BitBlt ( lpds->hDC, lpds->rcItem.left + ( LSTBTDX / 2 ),
|
|
lpds->rcItem.top, LSTBTDX, LSTBTDY,
|
|
hBtnDC,
|
|
SAV_PICT_X,
|
|
SAV_PICT_Y +
|
|
(( lpds->itemState & ODS_SELECTED ) &&
|
|
( lpds->itemState & ODS_FOCUS ) ? 0 : LSTBTDY ),
|
|
SRCCOPY );
|
|
}
|
|
|
|
SelectObject ( hBtnDC, hOldBitmap );
|
|
SetTextColor ( lpds->hDC, OldTextColor );
|
|
SetBkColor ( lpds->hDC, OldBkColor );
|
|
|
|
if ( lpds->itemAction & ODA_FOCUS &&
|
|
lpds->itemState & ODS_FOCUS )
|
|
{
|
|
DrawFocusRect ( lpds->hDC, &(lpds->rcItem) );
|
|
}
|
|
}
|
|
}
|
|
else if ( GETMDIINFO(hwnd)->DisplayMode == DSP_PREV )
|
|
{
|
|
if ( lpds->itemAction & ODA_FOCUS )
|
|
{
|
|
DrawFocusRect ( lpds->hDC, &(lpds->rcItem) );
|
|
}
|
|
|
|
if ( SendMessage ( GETMDIINFO(hwnd)->hWndListbox, LB_GETTEXT,
|
|
lpds->itemID, (LPARAM)(LPCSTR)&lpLE ) == LB_ERR )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( lpds->itemAction & ODA_DRAWENTIRE )
|
|
{
|
|
|
|
// erase any bogus leftover focusrect
|
|
if ( hBkBrush = CreateSolidBrush ( GetSysColor(COLOR_WINDOW)))
|
|
{
|
|
FillRect ( lpds->hDC, &(lpds->rcItem), hBkBrush );
|
|
DeleteObject ( hBkBrush );
|
|
}
|
|
|
|
tmprc.top = lpds->rcItem.top + PREVBRD;
|
|
tmprc.bottom = lpds->rcItem.top + PREVBRD + PREVBMPSIZ;
|
|
tmprc.left = lpds->rcItem.left + 5 * PREVBRD;
|
|
tmprc.right = lpds->rcItem.right - 5 * PREVBRD;
|
|
|
|
Rectangle (lpds->hDC,
|
|
tmprc.left,
|
|
tmprc.top,
|
|
tmprc.right,
|
|
tmprc.bottom );
|
|
|
|
// draw preview bitmap if available
|
|
if (lpLE->hbmp == NULL)
|
|
{
|
|
if (!lpLE->fTriedGettingPreview)
|
|
{
|
|
if (!GetPreviewBitmap (hwnd,
|
|
lpLE->name,
|
|
lpds->itemID))
|
|
{
|
|
lpLE->fTriedGettingPreview = FALSE;
|
|
|
|
InvalidateRect (lpds->hwndItem,
|
|
&(lpds->rcItem),
|
|
FALSE);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
lpLE->fTriedGettingPreview = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DrawIcon ( lpds->hDC,
|
|
// the magic '19' below is a function of the icon
|
|
tmprc.left + PREVBMPSIZ - 19,
|
|
tmprc.top,
|
|
hicLock);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hOldBitmap = SelectObject ( hBtnDC, lpLE->hbmp );
|
|
BitBlt ( lpds->hDC, tmprc.left+1, tmprc.top+1,
|
|
( tmprc.right - tmprc.left ) - 2,
|
|
( tmprc.bottom - tmprc.top ) - 2,
|
|
hBtnDC, 0, 0, SRCCOPY );
|
|
SelectObject ( hBtnDC, hOldBitmap );
|
|
}
|
|
|
|
// draw share icon in corner...
|
|
|
|
if ( IsShared ( lpLE ) && fShareEnabled )
|
|
{
|
|
DrawIcon (lpds->hDC,
|
|
tmprc.left - 10,
|
|
tmprc.top + PREVBMPSIZ - 24,
|
|
LoadIcon ( hInst, MAKEINTRESOURCE(IDSHAREICON)));
|
|
}
|
|
}
|
|
|
|
if ( lpds->itemAction & ( ODA_SELECT | ODA_DRAWENTIRE | ODA_FOCUS ))
|
|
{
|
|
tmprc = lpds->rcItem;
|
|
tmprc.left += PREVBRD;
|
|
tmprc.right -= PREVBRD;
|
|
tmprc.top += PREVBMPSIZ + 2 * PREVBRD;
|
|
tmprc.bottom--;
|
|
|
|
if ((lpds->itemState & ODS_SELECTED) &&
|
|
(lpds->itemState & ODS_FOCUS))
|
|
{
|
|
TextColor = GetSysColor ( COLOR_HIGHLIGHTTEXT );
|
|
BackColor = GetSysColor ( COLOR_HIGHLIGHT );
|
|
}
|
|
else
|
|
{
|
|
TextColor = GetSysColor ( COLOR_WINDOWTEXT );
|
|
BackColor = GetSysColor ( COLOR_WINDOW );
|
|
}
|
|
|
|
OldTextColor = SetTextColor ( lpds->hDC, TextColor );
|
|
OldBkColor = SetBkColor ( lpds->hDC, BackColor );
|
|
hOldFont = SelectObject ( lpds->hDC, hFontPreview );
|
|
|
|
if ( hBkBrush = CreateSolidBrush ( BackColor ))
|
|
{
|
|
FillRect ( lpds->hDC, &tmprc, hBkBrush );
|
|
DeleteObject ( hBkBrush );
|
|
}
|
|
|
|
|
|
DrawText (lpds->hDC,
|
|
&(lpLE->name[1]),
|
|
lstrlen(lpLE->name) -1,
|
|
&tmprc,
|
|
DT_CENTER | DT_WORDBREAK | DT_NOPREFIX );
|
|
|
|
SetTextColor ( lpds->hDC, OldTextColor );
|
|
SetBkColor ( lpds->hDC, OldBkColor );
|
|
SelectObject ( lpds->hDC, hOldFont );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ID_PAGEUP:
|
|
case ID_PAGEDOWN:
|
|
|
|
if (lpds->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))
|
|
{
|
|
if (lpds->itemState & ODS_SELECTED)
|
|
hOldBitmap = SelectObject (hBtnDC,
|
|
(lpds->CtlID==ID_PAGEUP)? hPgUpDBmp: hPgDnDBmp);
|
|
else
|
|
hOldBitmap = SelectObject (hBtnDC,
|
|
(lpds->CtlID==ID_PAGEUP)? hPgUpBmp: hPgDnBmp);
|
|
|
|
StretchBlt (lpds->hDC,
|
|
lpds->rcItem.top,
|
|
lpds->rcItem.left,
|
|
GetSystemMetrics (SM_CXVSCROLL),
|
|
GetSystemMetrics (SM_CYHSCROLL),
|
|
hBtnDC,
|
|
0,
|
|
0,
|
|
17, // x and y of resource bitmaps
|
|
17,
|
|
SRCCOPY);
|
|
|
|
SelectObject (hBtnDC, hOldBitmap);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
PERROR(TEXT("spurious WM_DRAWITEM ctlID %x\n\r"), lpds->CtlID );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// CreateNewListBox ///////////////////////////////
|
|
//
|
|
// this function creates a new ownerdraw listbox in one of
|
|
// two styles suitable for this app: multicolumn for the
|
|
// preview bitmap display, and single column for the description
|
|
// display preceeded by the little clipboard entry icons
|
|
|
|
HWND CreateNewListBox(
|
|
HWND hwnd,
|
|
DWORD style)
|
|
{
|
|
HWND hLB;
|
|
|
|
hLB = CreateWindow (TEXT("listbox"),
|
|
szNull,
|
|
WS_CHILD | LBS_STANDARD | LBS_NOINTEGRALHEIGHT | style,
|
|
0,
|
|
0,
|
|
100,
|
|
100,
|
|
hwnd,
|
|
(HMENU)ID_LISTBOX,
|
|
hInst,
|
|
0L );
|
|
|
|
if ( style & LBS_MULTICOLUMN )
|
|
SendMessage ( hLB, LB_SETCOLUMNWIDTH, PREVBMPSIZ + 10*PREVBRD, 0L );
|
|
|
|
return hLB;
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetClipboardFormatFromDDE ///////////////////////////
|
|
//
|
|
// This function accepts a ddeml data handle and uses the
|
|
// data contained in it to set the clipboard data in the specified
|
|
// format to the virtual clipboard associated with the supplied MDI
|
|
// child window handle. This could be the real clipboard if the MDI
|
|
// child window handle refers to the clipboard child window.
|
|
|
|
BOOL SetClipboardFormatFromDDE(
|
|
HWND hwnd,
|
|
UINT uiFmt,
|
|
HDDEDATA hDDE)
|
|
{
|
|
HANDLE hBitmap;
|
|
HANDLE hData;
|
|
LPBYTE lpData;
|
|
LPBYTE lpSrc;
|
|
BITMAP bitmap;
|
|
HPALETTE hPalette;
|
|
LPLOGPALETTE lpLogPalette;
|
|
DWORD cbData;
|
|
int err;
|
|
BOOL fOK = FALSE;
|
|
|
|
|
|
PINFO("SetClpFmtDDE: format %d, handle %ld | ", uiFmt, hDDE);
|
|
|
|
|
|
// Check for existing errors, clear the error flag
|
|
err = DdeGetLastError(idInst);
|
|
|
|
|
|
if (err != DMLERR_NO_ERROR)
|
|
{
|
|
PERROR(TEXT("Existing err %x\r\n"), err);
|
|
}
|
|
|
|
|
|
// get size of data
|
|
if (NULL == (lpSrc = DdeAccessData ( hDDE, &cbData )))
|
|
{
|
|
#if DEBUG
|
|
unsigned i;
|
|
|
|
i = DdeGetLastError(idInst);
|
|
PERROR(TEXT("DdeAccessData fail %d on handle %ld\r\n"), i, hDDE);
|
|
#endif
|
|
goto done;
|
|
}
|
|
|
|
|
|
PINFO(TEXT("%d bytes of data. "), cbData);
|
|
|
|
if (!(hData = GlobalAlloc(GHND, cbData)))
|
|
{
|
|
PERROR(TEXT("GlobalAlloc failed\n\r"));
|
|
goto done2;
|
|
}
|
|
|
|
|
|
if (!(lpData = GlobalLock(hData)))
|
|
{
|
|
PERROR(TEXT("GlobalLock failed\n\r"));
|
|
goto done2;
|
|
}
|
|
|
|
|
|
memcpy(lpData, lpSrc, cbData);
|
|
GlobalUnlock(hData);
|
|
|
|
|
|
|
|
// As when we write these we have to special case a few of
|
|
// these guys. This code and the write code should match in terms
|
|
// of the sizes and positions of data blocks being written out.
|
|
switch ( uiFmt )
|
|
{
|
|
case CF_METAFILEPICT:
|
|
{
|
|
HANDLE hMF;
|
|
HANDLE hMFP;
|
|
HANDLE hDataOut = NULL;
|
|
LPMETAFILEPICT lpMFP;
|
|
|
|
// Create the METAFILE with the bits we read in.
|
|
lpData = GlobalLock(hData);
|
|
if (hMF = SetMetaFileBitsEx(cbData - sizeof(WIN31METAFILEPICT),
|
|
lpData + sizeof(WIN31METAFILEPICT)))
|
|
{
|
|
// Alloc a METAFILEPICT header.
|
|
if (hMFP = GlobalAlloc(GHND, (DWORD)sizeof(METAFILEPICT)))
|
|
{
|
|
if (!(lpMFP = (LPMETAFILEPICT)GlobalLock(hMFP)))
|
|
{
|
|
PERROR(TEXT("Set...FromDDE: GlobalLock failed\n\r"));
|
|
GlobalFree(hMFP);
|
|
}
|
|
else
|
|
{
|
|
// Have to set this struct memberwise because it's packed
|
|
// as a WIN31METAFILEPICT in the data we get via DDE
|
|
lpMFP->hMF = hMF;
|
|
lpMFP->xExt =((WIN31METAFILEPICT *)lpData)->xExt;
|
|
lpMFP->yExt =((WIN31METAFILEPICT *)lpData)->yExt;
|
|
lpMFP->mm =((WIN31METAFILEPICT *)lpData)->mm;
|
|
|
|
GlobalUnlock(hMFP); /* Unlock the header */
|
|
hDataOut = hMFP; /* Stuff this in the clipboard */
|
|
fOK = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("SCFDDE: GlobalAlloc fail in MFP, %ld\r\n"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("SClipFDDE: SetMFBitsEx fail %ld\r\n"), GetLastError());
|
|
}
|
|
GlobalUnlock(hData);
|
|
|
|
hData = hDataOut;
|
|
break;
|
|
}
|
|
|
|
case CF_ENHMETAFILE:
|
|
// We get a block of memory containing enhmetafile bits in this case.
|
|
if (lpData = GlobalLock(hData))
|
|
{
|
|
HENHMETAFILE henh;
|
|
|
|
henh = SetEnhMetaFileBits(cbData, lpData);
|
|
|
|
if (NULL == henh)
|
|
{
|
|
PERROR(TEXT("SetEnhMFBits fail %d\r\n"), GetLastError());
|
|
}
|
|
else
|
|
{
|
|
fOK = TRUE;
|
|
}
|
|
|
|
GlobalUnlock(hData);
|
|
GlobalFree(hData);
|
|
|
|
hData = henh;
|
|
}
|
|
else
|
|
{
|
|
GlobalFree(hData);
|
|
hData = NULL;
|
|
}
|
|
break;
|
|
|
|
case CF_BITMAP:
|
|
if (!(lpData = GlobalLock(hData)))
|
|
{
|
|
GlobalFree(hData);
|
|
}
|
|
else
|
|
{
|
|
bitmap.bmType = ((WIN31BITMAP *)lpData)->bmType;
|
|
bitmap.bmWidth = ((WIN31BITMAP *)lpData)->bmWidth;
|
|
bitmap.bmHeight = ((WIN31BITMAP *)lpData)->bmHeight;
|
|
bitmap.bmWidthBytes = ((WIN31BITMAP *)lpData)->bmWidthBytes;
|
|
bitmap.bmPlanes = ((WIN31BITMAP *)lpData)->bmPlanes;
|
|
bitmap.bmBitsPixel = ((WIN31BITMAP *)lpData)->bmBitsPixel;
|
|
bitmap.bmBits = lpData + sizeof(WIN31BITMAP);
|
|
|
|
// If this fails we should avoid doing the SetClipboardData()
|
|
// below with the hData check.
|
|
hBitmap = CreateBitmapIndirect(&bitmap);
|
|
|
|
GlobalUnlock(hData);
|
|
GlobalFree(hData);
|
|
hData = hBitmap; // Stuff this in the clipboard
|
|
|
|
if (hBitmap)
|
|
{
|
|
fOK = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CF_PALETTE:
|
|
if (!(lpLogPalette = (LPLOGPALETTE)GlobalLock(hData)))
|
|
{
|
|
GlobalFree(hData);
|
|
DdeUnaccessData( hDDE );
|
|
DdeFreeDataHandle ( hDDE );
|
|
fOK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Create a logical palette.
|
|
if (!(hPalette = CreatePalette(lpLogPalette)))
|
|
{
|
|
GlobalUnlock(hData);
|
|
GlobalFree(hData);
|
|
}
|
|
else
|
|
{
|
|
GlobalUnlock(hData);
|
|
GlobalFree(hData);
|
|
|
|
hData = hPalette; // Stuff this into clipboard
|
|
fOK = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case DDE_DIB2BITMAP:
|
|
|
|
// convert dib to bitmap
|
|
{
|
|
HBITMAP hBmp;
|
|
|
|
hBmp = BitmapFromDib (hData,
|
|
VGetClipboardData (GETMDIINFO(hwnd)->pVClpbrd, CF_PALETTE));
|
|
|
|
GlobalFree (hData);
|
|
hData = hBmp;
|
|
|
|
uiFmt = CF_BITMAP;
|
|
|
|
fOK = TRUE;
|
|
break;
|
|
}
|
|
|
|
|
|
default:
|
|
fOK = TRUE;
|
|
}
|
|
|
|
|
|
if (!hData)
|
|
{
|
|
PERROR(TEXT("SetClipboardFormatFromDDE returning FALSE\n\r"));
|
|
}
|
|
|
|
|
|
if (GETMDIINFO(hwnd))
|
|
if (fOK)
|
|
{
|
|
PINFO(TEXT("SCFFDDE: Setting VClpD\r\n"));
|
|
VSetClipboardData( GETMDIINFO(hwnd)->pVClpbrd, uiFmt, hData);
|
|
}
|
|
else if (!(GETMDIINFO(hwnd)->flags & F_CLPBRD))
|
|
{
|
|
VSetClipboardData (GETMDIINFO(hwnd)->pVClpbrd, uiFmt,
|
|
INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
|
|
// No GlobalFree() call here, 'cause we've put hData on the clp
|
|
|
|
|
|
done2:
|
|
DdeUnaccessData(hDDE);
|
|
|
|
done:
|
|
DdeFreeDataHandle(hDDE);
|
|
|
|
return fOK;
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewWindow /////////////////////////////////////////////
|
|
//
|
|
// this function creates a new MDI child window. special
|
|
// case code detects if the window created is the special case
|
|
// clipboard MDI child window or the special case local clipbook
|
|
// window, this information is used to size the initial 2 windows
|
|
// to be tiled side-by-side
|
|
|
|
|
|
HWND NewWindow(VOID)
|
|
{
|
|
HWND hwnd;
|
|
MDICREATESTRUCT mcs;
|
|
|
|
mcs.szTitle = TEXT("");
|
|
mcs.szClass = szChild;
|
|
mcs.hOwner = hInst;
|
|
|
|
/* Use the default size for the window */
|
|
|
|
if ( !hwndClpbrd )
|
|
{
|
|
mcs.style = WS_MINIMIZE;
|
|
}
|
|
else
|
|
{
|
|
mcs.style = 0;
|
|
}
|
|
mcs.x = mcs.cx = CW_USEDEFAULT;
|
|
mcs.y = mcs.cy = CW_USEDEFAULT;
|
|
|
|
/* Set the style DWORD of the window to default */
|
|
|
|
// note not visible!
|
|
mcs.style |= ( WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CAPTION |
|
|
WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX |
|
|
WS_SYSMENU );
|
|
|
|
/* tell the MDI Client to create the child */
|
|
hwnd = (HWND)SendMessage (hwndMDIClient,
|
|
WM_MDICREATE,
|
|
0,
|
|
(LPARAM)(LPMDICREATESTRUCT)&mcs);
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
|
|
|
|
// AdjustMDIClientSize //////////////////////////////
|
|
//
|
|
// this function adjusts the size of the MDI client window
|
|
// when the application is resized according to whether the
|
|
// toolbar/status bar is visible, etc.
|
|
|
|
VOID AdjustMDIClientSize(VOID)
|
|
{
|
|
RECT rcApp;
|
|
RECT rcMDI;
|
|
|
|
|
|
if (IsIconic(hwndApp))
|
|
return;
|
|
|
|
GetClientRect (hwndApp, &rcApp);
|
|
|
|
|
|
rcMDI.top = 0;
|
|
rcMDI.bottom = rcApp.bottom - rcApp.top;
|
|
|
|
rcMDI.left = 0;
|
|
rcMDI.right = rcApp.right - rcApp.left;
|
|
|
|
MoveWindow (hwndMDIClient,
|
|
rcMDI.left - 1,
|
|
rcMDI.top + (fToolBar? (dyButtonBar +1): 0),
|
|
(rcMDI.right - rcMDI.left) + 2,
|
|
((rcMDI.bottom - rcMDI.top) - (fStatus?dyStatus:0)) -(fToolBar?(dyButtonBar +1):0),
|
|
TRUE);
|
|
|
|
if (fNeedToTileWindows )
|
|
{
|
|
SendMessage (hwndMDIClient, WM_MDITILE, 0, 0);
|
|
fNeedToTileWindows = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetConvDataItem ///////////////////////////////////
|
|
//
|
|
// this function retrieves the data item associated with the
|
|
// supplied topic and item from whatever local or remote host
|
|
// the MDI child window specified by the supplied handle is
|
|
// communicating with. It is used to get the preview bitmaps and
|
|
// to get individual format data.
|
|
//
|
|
// NOTE: caller should LockApp before calling this!
|
|
|
|
HDDEDATA GetConvDataItem(
|
|
HWND hwnd,
|
|
LPTSTR szTopic,
|
|
LPTSTR szItem,
|
|
UINT uiFmt)
|
|
{
|
|
HCONV hConv;
|
|
HSZ hszTopic;
|
|
HSZ hszItem;
|
|
HDDEDATA hRet = 0;
|
|
PMDIINFO pMDI;
|
|
|
|
|
|
PINFO(TEXT("GConvDI: %s ! %s, %x\r\n"), szTopic, szItem, uiFmt);
|
|
|
|
if (!( hszTopic = DdeCreateStringHandle ( idInst, szTopic, 0 )))
|
|
{
|
|
PERROR(TEXT("GetConvDataItem: DdeCreateStringHandle failed\n\r"));
|
|
return 0;
|
|
}
|
|
|
|
if (!(hszItem = DdeCreateStringHandle ( idInst, szItem, 0 )))
|
|
{
|
|
DdeFreeStringHandle ( idInst, hszTopic );
|
|
PERROR(TEXT("GetConvDataItem: DdeCreateStringHandle failed\n\r"));
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (!(pMDI = GETMDIINFO(hwnd)))
|
|
return 0;
|
|
|
|
if ( hConv = DdeConnect (idInst,
|
|
(uiFmt == cf_preview && !(pMDI->flags & F_LOCAL))?
|
|
pMDI->hszConvPartnerNP:
|
|
pMDI->hszConvPartner,
|
|
hszTopic,NULL ))
|
|
{
|
|
hRet = MySyncXact (NULL, 0L, hConv,
|
|
hszItem, uiFmt, XTYP_REQUEST, SHORT_SYNC_TIMEOUT, NULL );
|
|
if ( !hRet )
|
|
{
|
|
PERROR(TEXT("Transaction for (%s):(%s) failed: %x\n\r"),
|
|
szTopic, szItem, DdeGetLastError(idInst));
|
|
}
|
|
}
|
|
#if DEBUG
|
|
else
|
|
{
|
|
DdeQueryString ( idInst, GETMDIINFO(hwnd)->hszConvPartner,
|
|
szBuf, 128, CP_WINANSI );
|
|
PERROR(TEXT("GetConvDataItem: connect to %s|%s failed: %d\n\r"),
|
|
(LPTSTR)szBuf,
|
|
(LPTSTR)szTopic, DdeGetLastError(idInst) );
|
|
}
|
|
#endif
|
|
|
|
|
|
DdeDisconnect ( hConv );
|
|
DdeFreeStringHandle ( idInst, hszTopic );
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
// FUNCTION : MyMsgFilterProc
|
|
//
|
|
// PURPOSE : This filter proc gets called for each message we handle.
|
|
// This allows our application to properly dispatch messages
|
|
// that we might not otherwise see because of DDEMLs modal
|
|
// loop that is used while processing synchronous transactions.
|
|
//
|
|
// Generally, applications that only do synchronous transactions
|
|
// in response to user input (as this app does) does not need
|
|
// to install such a filter proc because it would be very rare
|
|
// that a user could command the app fast enough to cause
|
|
// problems. However, this is included as an example.
|
|
|
|
LRESULT PASCAL MyMsgFilterProc(
|
|
int nCode,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
|
|
|
|
if (( nCode == MSGF_DIALOGBOX || nCode == MSGF_MENU ) &&
|
|
((LPMSG)lParam)->message == WM_KEYDOWN &&
|
|
((LPMSG)lParam)->wParam == VK_F1 )
|
|
{
|
|
PostMessage ( hwndApp, WM_F1DOWN, nCode, 0L );
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
|
|
// MySyncXact ///////////////////////////////
|
|
//
|
|
// this function is a wrapper to DdeClientTransaction which
|
|
// performs some checks related to the Locked state of the app
|
|
|
|
HDDEDATA MySyncXact(
|
|
LPBYTE lpbData,
|
|
DWORD cbDataLen,
|
|
HCONV hConv,
|
|
HSZ hszItem,
|
|
UINT wFmt,
|
|
UINT wType,
|
|
DWORD dwTimeout,
|
|
LPDWORD lpdwResult)
|
|
{
|
|
HDDEDATA hDDE;
|
|
BOOL fAlreadyLocked;
|
|
UINT uiErr;
|
|
UINT DdeErr = 0;
|
|
DWORD dwTmp = 0;
|
|
|
|
#if DEBUG
|
|
if (dwTimeout != TIMEOUT_ASYNC)
|
|
{
|
|
dwTimeout +=10000;
|
|
}
|
|
#endif
|
|
|
|
|
|
// are we already in transaction?
|
|
|
|
if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
|
|
{
|
|
Sleep (2000);
|
|
ClearInput (hwndApp);
|
|
return 0L;
|
|
}
|
|
|
|
fAlreadyLocked = !LockApp(TRUE, NULL);
|
|
|
|
gXERR_Type = 0;
|
|
gXERR_Err = 0;
|
|
|
|
|
|
hDDE = DdeClientTransaction (lpbData,
|
|
cbDataLen,
|
|
hConv,
|
|
hszItem,
|
|
wFmt,
|
|
wType,
|
|
dwTimeout,
|
|
lpdwResult );
|
|
|
|
if (!hDDE)
|
|
{
|
|
DWORD size;
|
|
LPBYTE lpByte;
|
|
|
|
|
|
DdeErr = DdeGetLastError(idInst);
|
|
|
|
#if DEBUG
|
|
PERROR("MySyncXact fail err %d.\r\n", uiErr);
|
|
|
|
DdeQueryString (idInst, hszItem, lpbItem, 64, CP_WINANSI);
|
|
PINFO(TEXT("Parameters: data at %lx (%s), len %ld, HCONV %lx\r\n"),
|
|
lpbData, (CF_TEXT == wFmt && lpbData) ? lpbData : TEXT("Not text"),
|
|
cbDataLen, hConv);
|
|
|
|
PINFO(TEXT("item %lx (%s), fmt %d, type %d, timeout %ld\r\n"),
|
|
hszItem, lpbItem, wFmt, wType, dwTimeout);
|
|
#endif
|
|
|
|
|
|
//
|
|
// There was an error in the transaction, let's ask
|
|
// the server what was it.
|
|
//
|
|
|
|
hDDE = DdeClientTransaction (NULL,
|
|
0L,
|
|
hConv,
|
|
hszErrorRequest,
|
|
CF_TEXT,
|
|
XTYP_REQUEST,
|
|
SHORT_SYNC_TIMEOUT,
|
|
NULL);
|
|
|
|
uiErr = DdeGetLastError (idInst);
|
|
|
|
if (lpByte = DdeAccessData (hDDE, &size))
|
|
sscanf (lpByte, XERR_FORMAT, &gXERR_Type, &gXERR_Err);
|
|
|
|
DdeUnaccessData (hDDE);
|
|
DdeFreeDataHandle (hDDE);
|
|
|
|
hDDE = 0;
|
|
}
|
|
|
|
|
|
if (!gXERR_Type && DdeErr)
|
|
{
|
|
gXERR_Type = XERRT_DDE;
|
|
gXERR_Err = DdeErr;
|
|
}
|
|
|
|
|
|
if (!fAlreadyLocked)
|
|
{
|
|
LockApp(FALSE, NULL);
|
|
}
|
|
|
|
SetEvent (hXacting);
|
|
|
|
return hDDE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* RequestXactError
|
|
*
|
|
* Ask the server for error code.
|
|
*/
|
|
|
|
void RequestXactError(
|
|
HCONV hConv)
|
|
{
|
|
HDDEDATA hDDE;
|
|
BOOL fAlreadyLocked;
|
|
UINT uiErr;
|
|
UINT DdeErr = 0;
|
|
DWORD size;
|
|
LPBYTE lpByte;
|
|
|
|
|
|
|
|
// Are we already in transaction?
|
|
|
|
if (WAIT_TIMEOUT == WaitForSingleObject (hXacting, 0))
|
|
{
|
|
Sleep (2000);
|
|
ClearInput (hwndApp);
|
|
return;
|
|
}
|
|
|
|
fAlreadyLocked = !LockApp(TRUE, NULL);
|
|
|
|
gXERR_Type = 0;
|
|
gXERR_Err = 0;
|
|
|
|
DdeErr = DdeGetLastError(idInst);
|
|
|
|
|
|
hDDE = DdeClientTransaction (NULL,
|
|
0L,
|
|
hConv,
|
|
hszErrorRequest,
|
|
CF_TEXT,
|
|
XTYP_REQUEST,
|
|
SHORT_SYNC_TIMEOUT,
|
|
NULL);
|
|
|
|
uiErr = DdeGetLastError (idInst);
|
|
|
|
|
|
if (lpByte = DdeAccessData (hDDE, &size))
|
|
sscanf (lpByte, XERR_FORMAT, &gXERR_Type, &gXERR_Err);
|
|
|
|
DdeUnaccessData (hDDE);
|
|
DdeFreeDataHandle (hDDE);
|
|
|
|
|
|
if (!gXERR_Type && DdeErr)
|
|
{
|
|
gXERR_Type = XERRT_DDE;
|
|
gXERR_Err = DdeErr;
|
|
}
|
|
|
|
|
|
if (!fAlreadyLocked)
|
|
{
|
|
LockApp(FALSE, NULL);
|
|
}
|
|
|
|
SetEvent (hXacting);
|
|
}
|
|
|
|
|
|
|
|
// ResetScrollInfo ///////////////////////////
|
|
//
|
|
// this function resets the scroll information of the
|
|
// MDI child window designated by the supplied handle
|
|
|
|
VOID ResetScrollInfo(
|
|
HWND hwnd)
|
|
{
|
|
PMDIINFO pMDI = GETMDIINFO(hwnd);
|
|
|
|
if (!pMDI)
|
|
return;
|
|
|
|
// Invalidate object info; reset scroll position to 0.
|
|
pMDI->cyScrollLast = -1L;
|
|
pMDI->cyScrollNow = 0L;
|
|
pMDI->cxScrollLast = -1;
|
|
pMDI->cxScrollNow = 0;
|
|
|
|
// Range is set in case CF_OWNERDISPLAY owner changed it.
|
|
PINFO(TEXT("SETSCROLLRANGE for window '%s'\n\r"),
|
|
(LPTSTR)(pMDI->szBaseName) );
|
|
|
|
SetScrollRange (pMDI->hwndVscroll, SB_CTL, 0, VPOSLAST, FALSE);
|
|
SetScrollRange (pMDI->hwndHscroll, SB_CTL, 0, HPOSLAST, FALSE);
|
|
SetScrollPos (pMDI->hwndVscroll, SB_CTL, (int)(pMDI->cyScrollNow), TRUE);
|
|
SetScrollPos (pMDI->hwndHscroll, SB_CTL, pMDI->cxScrollNow, TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsShared ///////////////////////////////////
|
|
//
|
|
// this function checks the shared state of the ownerdraw
|
|
// listbox entry denoted by the supplied pointer. Shared/nonshared
|
|
// status is expressed as a 1 character prefix to the description string
|
|
//
|
|
// return TRUE if shared, false otherwise
|
|
|
|
BOOL IsShared(
|
|
LPLISTENTRY lpLE)
|
|
{
|
|
if (!lpLE)
|
|
return FALSE;
|
|
|
|
if ( lpLE->name[0] == SHR_CHAR )
|
|
return TRUE;
|
|
|
|
#if DEBUG
|
|
if ( lpLE->name[0] != UNSHR_CHAR )
|
|
PERROR(TEXT("bad prefix char in share name: %s\n\r"),
|
|
(LPTSTR)lpLE->name );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
// SetShared //////////////////////////////////////////
|
|
//
|
|
// sets shared state to fShared, returns previous state
|
|
|
|
BOOL SetShared(
|
|
LPLISTENTRY lpLE,
|
|
BOOL fShared)
|
|
{
|
|
BOOL fSave;
|
|
|
|
fSave = lpLE->name[0] == SHR_CHAR ? TRUE : FALSE;
|
|
lpLE->name[0] = ( fShared ? SHR_CHAR : UNSHR_CHAR );
|
|
|
|
return fSave;
|
|
}
|
|
|
|
|
|
|
|
|
|
// LockApp ////////////////////////////////////////////
|
|
//
|
|
// this function effectively disables the windows UI during
|
|
// synchronous ddeml transactions to prevent the user from initiating
|
|
// another transaction or causing the window procedure of this app
|
|
// or another application to be re-entered in a way that could cause
|
|
// failures... A primary example is that sometimes we are forced to
|
|
// go into a ddeml transaction with the clipboard open... this app
|
|
// and other apps must not be caused to access the clipboard during that
|
|
// time, so this mechanism emulates the hourglass...
|
|
//
|
|
// NOTE: do not call LockApp in a section of code where the
|
|
// cursor is already captured, such as in response to a scroll
|
|
// message, or the releasecapture during unlock will cause strange and
|
|
// bad things to happen.
|
|
|
|
|
|
BOOL LockApp(
|
|
BOOL fLock,
|
|
LPTSTR lpszComment)
|
|
{
|
|
static HCURSOR hOldCursor;
|
|
BOOL fOK = FALSE;
|
|
|
|
|
|
if (lpszComment)
|
|
{
|
|
SetStatusBarText( lpszComment );
|
|
}
|
|
|
|
if ( fLock == TRUE )
|
|
{
|
|
if ( fAppLockedState )
|
|
{
|
|
PERROR(TEXT("LockApp(TRUE): already locked\n\r"));
|
|
}
|
|
else
|
|
{
|
|
hOldCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ));
|
|
|
|
SetCapture ( hwndDummy );
|
|
EnableWindow ( hwndApp, FALSE );
|
|
|
|
fOK = TRUE;
|
|
fAppLockedState = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !fAppLockedState )
|
|
{
|
|
PERROR(TEXT("LockApp(FALSE): not locked\n\r"));
|
|
}
|
|
else
|
|
{
|
|
|
|
ClearInput (hwndApp);
|
|
|
|
EnableWindow ( hwndApp, TRUE );
|
|
ReleaseCapture ();
|
|
|
|
SetCursor ( hOldCursor );
|
|
|
|
fOK = TRUE;
|
|
|
|
// take care of any deferred clipboard update requests
|
|
if ( fClipboardNeedsPainting )
|
|
{
|
|
PostMessage ( hwndApp, WM_DRAWCLIPBOARD, 0, 0L );
|
|
}
|
|
|
|
fAppLockedState = FALSE;
|
|
}
|
|
}
|
|
|
|
return fOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ForceRenderAll ///////////////////////////////////
|
|
//
|
|
// this function forces a complete rendering of any delayed
|
|
// render clipboard formats
|
|
BOOL ForceRenderAll(
|
|
HWND hwnd,
|
|
PVCLPBRD pVclp)
|
|
{
|
|
HANDLE h;
|
|
UINT uiFmt;
|
|
|
|
if ( !VOpenClipboard ( pVclp, hwnd ))
|
|
{
|
|
PERROR(TEXT("Can't open clipboard in ForceRenderAll\n\r"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
for ( uiFmt = VEnumClipboardFormats( pVclp, 0); uiFmt;
|
|
uiFmt = VEnumClipboardFormats( pVclp, uiFmt))
|
|
{
|
|
PINFO(TEXT("ForceRenderAll: force rendering %x\n\r"), uiFmt );
|
|
h = VGetClipboardData ( pVclp, uiFmt );
|
|
}
|
|
|
|
VCloseClipboard ( pVclp );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL UpdateNofMStatus(
|
|
HWND hwnd)
|
|
{
|
|
HWND hwndlistbox;
|
|
int total = 0;
|
|
int sel = LB_ERR;
|
|
|
|
|
|
if (hwnd == NULL)
|
|
{
|
|
SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)NULL );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
if (!GETMDIINFO(hwnd))
|
|
return FALSE;
|
|
|
|
|
|
if (GETMDIINFO(hwnd)->flags & F_CLPBRD)
|
|
{
|
|
SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPTSTR) szSysClpBrd );
|
|
return TRUE;
|
|
}
|
|
|
|
if ( IsWindow( hwndlistbox = GETMDIINFO(hwnd)->hWndListbox ) )
|
|
{
|
|
total = (int)SendMessage ( hwndlistbox, LB_GETCOUNT, (WPARAM)0, 0L );
|
|
sel = (int)SendMessage ( hwndlistbox, LB_GETCURSEL, 0, 0L);
|
|
}
|
|
|
|
if ( sel == (int)LB_ERR )
|
|
{
|
|
if ( total == 1 )
|
|
SendMessage (hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szPageFmt);
|
|
else
|
|
{
|
|
StringCchPrintf( szBuf, SZBUFSIZ, szPageFmtPl, total );
|
|
SendMessage (hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szBuf );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintf(szBuf, SZBUFSIZ, szPageOfPageFmt, sel+1, total );
|
|
SendMessage ( hwndStatus, SB_SETTEXT, 0, (LPARAM)(LPCSTR)szBuf );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL RestoreAllSavedConnections(void)
|
|
{
|
|
TCHAR szName[80];
|
|
BOOL ret = TRUE;
|
|
unsigned i;
|
|
|
|
i = lstrlen(szConn);
|
|
|
|
if (NULL != hkeyRoot)
|
|
{
|
|
DWORD dwSize = 80;
|
|
DWORD iSubkey = 0;
|
|
|
|
while (ERROR_SUCCESS == RegEnumKeyEx(hkeyRoot, iSubkey,
|
|
szName, &dwSize, NULL, NULL, NULL, NULL) )
|
|
{
|
|
if (0 == memcmp(szName, szConn, i))
|
|
{
|
|
PINFO(TEXT("Restoring connection to '%s'\n\r"), szName + i);
|
|
|
|
if ( !CreateNewRemoteWindow ( szName + i, FALSE ) )
|
|
{
|
|
TCHAR szWindowName[80];
|
|
|
|
// remove re-connect entry
|
|
RegDeleteKey(hkeyRoot, szName);
|
|
|
|
StringCchCopy(szWindowName, 80, szWindows);
|
|
StringCchCat( szWindowName, 80, szName + i);
|
|
RegDeleteKey(hkeyRoot, szWindowName);
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
dwSize = 80;
|
|
iSubkey++;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CreateNewRemoteWindow(
|
|
LPTSTR szMachineName,
|
|
BOOL fReconnect)
|
|
{
|
|
WINDOWPLACEMENT wpl;
|
|
HWND hwndc;
|
|
PMDIINFO pMDIc;
|
|
|
|
|
|
// make new window active
|
|
hwndc = NewWindow();
|
|
if (NULL == hwndc)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!(pMDIc = GETMDIINFO(hwndc)))
|
|
return FALSE;
|
|
|
|
|
|
// save base name for window
|
|
StringCchCopy( pMDIc->szBaseName, (MAX_COMPUTERNAME_LENGTH+1)*2, szMachineName);
|
|
StringCchCopy( pMDIc->szComputerName, MAX_COMPUTERNAME_LENGTH + 1, szMachineName);
|
|
|
|
StringCchPrintf ( szBuf, SZBUFSIZ, TEXT("%s\\%s"), (LPTSTR)szMachineName, (LPTSTR)szNDDEcode);
|
|
|
|
pMDIc->hszConvPartner = DdeCreateStringHandle ( idInst, szBuf, 0 );
|
|
|
|
PINFO(TEXT("Trying to talk to %s\r\n"),szBuf);
|
|
|
|
StringCchPrintf ( szBuf, SZBUFSIZ, TEXT("%s\\%s"), (LPTSTR)szMachineName, (LPTSTR)szNDDEcode1 );
|
|
pMDIc->hszConvPartnerNP = DdeCreateStringHandle ( idInst, szBuf, 0 );
|
|
|
|
PINFO(TEXT("NP = %s\r\n"),szBuf);
|
|
|
|
#if DEBUG
|
|
DdeQueryString(idInst, hszSystem, szBuf, 128, CP_WINANSI);
|
|
PINFO(TEXT("Topic = %s\r\n"), szBuf);
|
|
|
|
PINFO(TEXT("Existing err = %lx\r\n"), DdeGetLastError(idInst));
|
|
#endif
|
|
|
|
pMDIc->hExeConv = InitSysConv (hwndc, pMDIc->hszConvPartner, hszClpBookShare, FALSE);
|
|
|
|
|
|
if ( pMDIc->hExeConv )
|
|
{
|
|
if ( UpdateListBox ( hwndc, pMDIc->hExeConv ))
|
|
{
|
|
StringCchPrintf(szBuf, SZBUFSIZ, szClipBookOnFmt, (LPTSTR)(pMDIc->szBaseName) );
|
|
SetWindowText ( hwndc, szBuf );
|
|
|
|
if ( ReadWindowPlacement ( pMDIc->szBaseName, &wpl ))
|
|
{
|
|
wpl.length = sizeof(WINDOWPLACEMENT);
|
|
wpl.flags = WPF_SETMINPOSITION;
|
|
SetWindowPlacement ( hwndc, &wpl );
|
|
UpdateWindow ( hwndc );
|
|
}
|
|
else
|
|
{
|
|
ShowWindow ( hwndc, SW_SHOWNORMAL );
|
|
}
|
|
|
|
ShowWindow ( pMDIc->hWndListbox, SW_SHOW );
|
|
SendMessage ( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)hwndc, 0L );
|
|
SendMessage ( hwndMDIClient, WM_MDISETMENU, (WPARAM) TRUE, 0L );
|
|
|
|
hwndActiveChild = hwndc;
|
|
pActiveMDI = GETMDIINFO(hwndc);
|
|
|
|
if ( fReconnect )
|
|
{
|
|
TCHAR szName[80];
|
|
DWORD dwData;
|
|
|
|
StringCchCopy(szName, 80, szConn);
|
|
StringCchCat( szName, 80, szBuf);
|
|
|
|
dwData = pMDIc->DisplayMode == DSP_LIST ? 1 : 2;
|
|
|
|
RegSetValueEx(hkeyRoot, szName, 0L, REG_DWORD,
|
|
(LPBYTE)&dwData, sizeof(dwData));
|
|
|
|
PINFO(TEXT("saving connection: '%s'\n\r"), (LPTSTR)szBuf );
|
|
}
|
|
else
|
|
{
|
|
TCHAR szName[80];
|
|
DWORD dwData;
|
|
DWORD dwDataSize = sizeof(dwData);
|
|
|
|
StringCchCopy(szName, 80, szConn);
|
|
StringCchCat( szName, 80, pMDIc->szBaseName);
|
|
|
|
RegQueryValueEx(hkeyRoot, szName, NULL, NULL,
|
|
(LPBYTE)&dwData, &dwDataSize);
|
|
|
|
if (2 == dwData)
|
|
{
|
|
SendMessage ( hwndApp, WM_COMMAND, IDM_PREVIEWS, 0L );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("UpdateListBox failed\n\r"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned uiErr;
|
|
|
|
#if DEBUG
|
|
DdeQueryString(idInst, pMDIc->hszConvPartner, szBuf, 128, CP_WINANSI);
|
|
#endif
|
|
|
|
uiErr = DdeGetLastError(idInst);
|
|
PERROR(TEXT("Can't find %s|System. Error #%x\n\r"),(LPTSTR)szBuf, uiErr );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
#define MB_SNDMASK (MB_ICONHAND|MB_ICONQUESTION|MB_ICONASTERISK|MB_ICONEXCLAMATION)
|
|
|
|
/*
|
|
* MessageBoxID
|
|
*
|
|
* Display a message box with strings specified by
|
|
* TextID and TitleID.
|
|
*/
|
|
|
|
int MessageBoxID(
|
|
HANDLE hInstance,
|
|
HWND hwndParent,
|
|
UINT TextID,
|
|
UINT TitleID,
|
|
UINT fuStyle)
|
|
{
|
|
LoadString (hInstance, TextID, szBuf, SZBUFSIZ);
|
|
LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
|
|
|
|
MessageBeep (fuStyle & MB_SNDMASK);
|
|
return MessageBox (hwndParent, szBuf, szBuf2, fuStyle);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* NDdeMessageBox
|
|
*
|
|
* Display a message box with NDde error
|
|
* string specified by errCode and title
|
|
* string specified by TitleID.
|
|
*/
|
|
|
|
int NDdeMessageBox(
|
|
HANDLE hInstance,
|
|
HWND hwnd,
|
|
UINT errCode,
|
|
UINT TitleID,
|
|
UINT fuStyle)
|
|
{
|
|
if (!errCode)
|
|
return IDOK;
|
|
|
|
NDdeGetErrorString (errCode, szBuf, SZBUFSIZ);
|
|
LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
|
|
|
|
MessageBeep (fuStyle & MB_SNDMASK);
|
|
return MessageBox (hwnd, szBuf, szBuf2, fuStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* SysMessageBox
|
|
*
|
|
* Display a messag box for system message
|
|
* strings specified by dwErr and titl string
|
|
* specified by TitleID.
|
|
*/
|
|
|
|
int SysMessageBox(
|
|
HANDLE hInstance,
|
|
HWND hwnd,
|
|
DWORD dwErr,
|
|
UINT TitleID,
|
|
UINT fuStyle)
|
|
{
|
|
DWORD dwR;
|
|
LPTSTR lpBuffer = NULL;
|
|
DWORD dwSize = 20;
|
|
|
|
if (dwErr == NO_ERROR)
|
|
return IDOK;
|
|
|
|
dwR = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER|
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwErr,
|
|
0,
|
|
(LPTSTR)&lpBuffer,
|
|
dwSize,
|
|
NULL);
|
|
if (0 < dwR)
|
|
{
|
|
LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
|
|
|
|
MessageBeep (fuStyle & MB_SNDMASK);
|
|
dwR = MessageBox (hwnd, lpBuffer, szBuf2, fuStyle);
|
|
|
|
LocalFree (lpBuffer);
|
|
}
|
|
|
|
return dwR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* XactMessageBox
|
|
*
|
|
* Display a message box for error
|
|
* occured in an transaction. MySyncXact
|
|
* must be called to do the transaction
|
|
* before calling this function.
|
|
*/
|
|
|
|
int XactMessageBox(
|
|
HANDLE hInstance,
|
|
HWND hwnd,
|
|
UINT TitleID,
|
|
UINT fuStyle)
|
|
{
|
|
|
|
switch (gXERR_Type)
|
|
{
|
|
case XERRT_NDDE:
|
|
return NDdeMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
|
|
case XERRT_DDE:
|
|
return DdeMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
|
|
case XERRT_SYS:
|
|
return SysMessageBox (hInstance, hwnd, gXERR_Err, TitleID, fuStyle);
|
|
default:
|
|
return IDOK;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* DdeNessageBox
|
|
*
|
|
* Displays a message box for DDE
|
|
* error strings specified by errCode
|
|
* and title string spcified by TitleID.
|
|
*/
|
|
|
|
int DdeMessageBox(
|
|
HANDLE hInstance,
|
|
HWND hwnd,
|
|
UINT errCode,
|
|
UINT TitleID,
|
|
UINT fuStyle)
|
|
{
|
|
TCHAR szErr[1024];
|
|
|
|
|
|
switch (errCode)
|
|
{
|
|
case DMLERR_ADVACKTIMEOUT:
|
|
case DMLERR_DATAACKTIMEOUT:
|
|
case DMLERR_EXECACKTIMEOUT:
|
|
case DMLERR_POKEACKTIMEOUT:
|
|
case DMLERR_UNADVACKTIMEOUT:
|
|
case DMLERR_NO_CONV_ESTABLISHED:
|
|
if (hwnd == hwndLocal)
|
|
LoadString (hInstance, IDS_NOCLPBOOK, szBuf, SZBUFSIZ);
|
|
else
|
|
LoadString (hInstance, IDS_DATAUNAVAIL, szBuf, SZBUFSIZ);
|
|
break;
|
|
|
|
case DMLERR_NOTPROCESSED:
|
|
case DMLERR_BUSY:
|
|
case DMLERR_DLL_NOT_INITIALIZED:
|
|
case DMLERR_DLL_USAGE:
|
|
case DMLERR_INVALIDPARAMETER:
|
|
case DMLERR_LOW_MEMORY:
|
|
case DMLERR_MEMORY_ERROR:
|
|
case DMLERR_POSTMSG_FAILED:
|
|
case DMLERR_REENTRANCY:
|
|
case DMLERR_SERVER_DIED:
|
|
case DMLERR_SYS_ERROR:
|
|
case DMLERR_UNFOUND_QUEUE_ID:
|
|
LoadString (hInstance, IDS_INTERNALERR, szBuf, SZBUFSIZ);
|
|
break;
|
|
default:
|
|
return IDOK;
|
|
}
|
|
|
|
LoadString (hInstance, TitleID, szBuf2, SZBUFSIZ);
|
|
|
|
StringCchPrintf (szErr, 1024, "%s (%#x)", szBuf, errCode);
|
|
|
|
MessageBeep (fuStyle & MB_SNDMASK);
|
|
return MessageBox (hwnd, szErr, szBuf2, fuStyle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* ClearInput
|
|
*
|
|
* Removes all keyboard and mouse messages
|
|
* from message queue
|
|
*/
|
|
|
|
void ClearInput (HWND hWnd)
|
|
{
|
|
MSG Msg;
|
|
|
|
while (PeekMessage (&Msg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE));
|
|
while (PeekMessage (&Msg, hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
|
|
}
|
|
|
|
|
|
|
|
|
|
PDATAREQ CreateNewDataReq (void)
|
|
{
|
|
return (PDATAREQ) GlobalAlloc (GPTR, sizeof(DATAREQ));
|
|
}
|
|
|
|
|
|
|
|
BOOL DeleteDataReq(
|
|
PDATAREQ pDataReq)
|
|
{
|
|
return ((HGLOBAL)pDataReq == GlobalFree (pDataReq));
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Purpose: Handle data returned from CLIPSRV via DDE.
|
|
//
|
|
// Parameters:
|
|
// hData - The data handle the XTYP_XACT_COMPLETE message gave us,
|
|
// or 0L if we got XTYP_DISCONNECT instead.
|
|
//
|
|
// pDataReq - Pointer to a DATAREQ struct containing info about what
|
|
// we wanted the data for. This is gotten via DdeGetUserHandle.
|
|
//
|
|
// Returns:
|
|
// TRUE on success, FALSE on failure.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL ProcessDataReq(
|
|
HDDEDATA hData,
|
|
PDATAREQ pDataReq)
|
|
{
|
|
LPLISTENTRY lpLE;
|
|
LPSTR lpwszList;
|
|
LPSTR q;
|
|
HCURSOR hSaveCursor;
|
|
DWORD cbDataLen;
|
|
UINT tmp;
|
|
PMDIINFO pMDI;
|
|
UINT uiErr;
|
|
BOOL bRet = FALSE;
|
|
|
|
|
|
hSaveCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
|
|
|
|
|
|
PINFO("PDR:");
|
|
|
|
if ( !pDataReq || !IsWindow(pDataReq->hwndMDI) )
|
|
{
|
|
PERROR(TEXT("ProcessDataReq: bogus DATAREQ\n\r"));
|
|
goto done;
|
|
}
|
|
|
|
|
|
if (!hData)
|
|
{
|
|
PERROR("ProcessDataReq: Woe, woe, we have gotten null data!\r\n");
|
|
DumpDataReq(pDataReq);
|
|
|
|
|
|
switch (pDataReq->rqType)
|
|
{
|
|
case RQ_COPY:
|
|
MessageBoxID (hInst, hwndApp, IDS_DATAUNAVAIL, IDS_APPNAME,
|
|
MB_OK | MB_ICONHAND);
|
|
break;
|
|
case RQ_PREVBITMAP:
|
|
// We still have to display the lock icon.
|
|
SetBitmapToListboxEntry (hData, pDataReq->hwndList, pDataReq->iListbox);
|
|
break;
|
|
}
|
|
|
|
goto done;;
|
|
}
|
|
|
|
|
|
if (!(pMDI = GETMDIINFO(pDataReq->hwndMDI)))
|
|
goto done;
|
|
|
|
|
|
switch ( pDataReq->rqType )
|
|
{
|
|
case RQ_PREVBITMAP:
|
|
PINFO("Got bitmap for item %d in %x\r\n",pDataReq->iListbox,
|
|
pDataReq->hwndList);
|
|
SetBitmapToListboxEntry( hData, pDataReq->hwndList, pDataReq->iListbox);
|
|
InitializeMenu (GetMenu (hwndApp));
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case RQ_EXECONV:
|
|
// must be from disconnect
|
|
GETMDIINFO(pDataReq->hwndMDI)->hExeConv = 0L;
|
|
PINFO(TEXT("setting hExeConv NULL!\n\r"));
|
|
break;
|
|
|
|
case RQ_COPY:
|
|
PINFO("RQ_COPY:");
|
|
if ( hData == FALSE )
|
|
{
|
|
uiErr = DdeGetLastError (idInst);
|
|
PERROR(TEXT("REQUEST for format list failed: %x\n\r"), uiErr);
|
|
DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
|
|
break;
|
|
}
|
|
|
|
lpwszList = DdeAccessData ( hData, &cbDataLen );
|
|
|
|
if ( !lpwszList )
|
|
{
|
|
uiErr = DdeGetLastError (idInst);
|
|
DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
|
|
break;
|
|
}
|
|
|
|
PINFO(TEXT("formatlist:>%ws<\n\r"), lpwszList );
|
|
// this client now becomes the clipboard owner!!!
|
|
|
|
if (SyncOpenClipboard (hwndApp) == TRUE)
|
|
{
|
|
BOOL bHasBitmap = FALSE;
|
|
BOOL bLocked;
|
|
|
|
// Need to lock app while we fill the clipboard with formats,
|
|
// else hwndClpbrd will try to frantically try to redraw while
|
|
// we're doing it. Since hwndClpbrd needs to openclipboard() to
|
|
// do that, we don't want it to.
|
|
bLocked = LockApp(TRUE, szNull);
|
|
|
|
// reset clipboard view format to auto
|
|
pMDI->CurSelFormat = CBM_AUTO;
|
|
|
|
EmptyClipboard();
|
|
|
|
hwndClpOwner = pDataReq->hwndMDI;
|
|
PINFO(TEXT("Formats:"));
|
|
|
|
if (pDataReq->wFmt != CF_TEXT)
|
|
{
|
|
PERROR(TEXT("Format %d, expected CF_TEXT!\r\n"), pDataReq->wFmt);
|
|
}
|
|
|
|
|
|
for (q = strtokA(lpwszList, "\t");q;q = strtokA(NULL, "\t"))
|
|
{
|
|
PINFO(TEXT("[%s] "),q);
|
|
tmp = MyGetFormat(q, GETFORMAT_DONTLIE);
|
|
if (0 == tmp)
|
|
{
|
|
PERROR(TEXT("MyGetFormat failure!\r\n"));
|
|
}
|
|
else
|
|
{
|
|
switch (tmp)
|
|
{
|
|
case CF_DIB:
|
|
// DDBitmap can be converted from Dib.
|
|
SetClipboardData (CF_BITMAP, NULL);
|
|
default:
|
|
SetClipboardData (tmp, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
PINFO("\r\n");
|
|
|
|
SyncCloseClipboard();
|
|
|
|
if (bLocked)
|
|
LockApp (FALSE, szNull);
|
|
|
|
|
|
// Redraw clipboard window.
|
|
if (hwndClpbrd)
|
|
{
|
|
InvalidateRect(hwndClpbrd, NULL, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("ProcessDataReq: unable to open clipboard\n\r"));
|
|
}
|
|
|
|
DdeUnaccessData ( hData );
|
|
DdeFreeDataHandle ( hData );
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case RQ_SETPAGE:
|
|
PINFO(TEXT("RQ_SETPAGE:"));
|
|
|
|
if ( hData == FALSE )
|
|
{
|
|
uiErr = DdeGetLastError (idInst);
|
|
PERROR(TEXT("vclip: REQUEST for format list failed: %x\n\r"), idInst);
|
|
DdeMessageBox (hInst, pDataReq->hwndMDI, idInst, IDS_APPNAME, MB_OK|MB_ICONEXCLAMATION);
|
|
break;
|
|
}
|
|
|
|
if ( SendMessage ( pMDI->hWndListbox,
|
|
LB_GETTEXT, pDataReq->iListbox,
|
|
(LPARAM)(LPCSTR)&lpLE) == LB_ERR )
|
|
{
|
|
PERROR(TEXT("IDM_COPY: bad listbox index: %d\n\r"), pDataReq->iListbox );
|
|
break;
|
|
}
|
|
|
|
lpwszList = DdeAccessData ( hData, &cbDataLen );
|
|
|
|
if ( !lpwszList )
|
|
{
|
|
uiErr = DdeGetLastError (idInst);
|
|
DdeMessageBox (hInst, pDataReq->hwndMDI, uiErr, IDS_APPNAME, MB_OK | MB_ICONEXCLAMATION );
|
|
break;
|
|
}
|
|
|
|
if ( VOpenClipboard ( pMDI->pVClpbrd, pDataReq->hwndMDI ) == TRUE )
|
|
{
|
|
BOOL bHasBitmap = FALSE;
|
|
|
|
VEmptyClipboard( pMDI->pVClpbrd );
|
|
|
|
for (q = strtokA(lpwszList, "\t");q;q = strtokA(NULL,"\t"))
|
|
{
|
|
tmp = MyGetFormat(q, GETFORMAT_DONTLIE);
|
|
|
|
switch (tmp)
|
|
{
|
|
case CF_DIB:
|
|
// DDBitmap can be converted from Dib.
|
|
VSetClipboardData (pMDI->pVClpbrd, CF_BITMAP, NULL);
|
|
default:
|
|
VSetClipboardData (pMDI->pVClpbrd, tmp, NULL);
|
|
}
|
|
}
|
|
|
|
VCloseClipboard( pMDI->pVClpbrd );
|
|
}
|
|
else
|
|
{
|
|
PERROR(TEXT("ProcessDataReq: unable to open Vclipboard\n\r"));
|
|
}
|
|
|
|
DdeUnaccessData ( hData );
|
|
DdeFreeDataHandle ( hData );
|
|
|
|
// set proper window text
|
|
if ( pMDI->flags & F_LOCAL )
|
|
{
|
|
StringCchPrintf( szBuf, SZBUFSIZ, TEXT("%s - %s"), szLocalClpBk, &(lpLE->name[1]) );
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintf( szBuf, SZBUFSIZ, TEXT("%s - %s"), (pMDI->szBaseName), &(lpLE->name[1]) );
|
|
}
|
|
SetWindowText ( pDataReq->hwndMDI, szBuf );
|
|
|
|
SetFocus ( pDataReq->hwndMDI );
|
|
pMDI->CurSelFormat = CBM_AUTO;
|
|
pMDI->fDisplayFormatChanged = TRUE;
|
|
ResetScrollInfo ( pDataReq->hwndMDI );
|
|
|
|
// means data is for going into page mode
|
|
if ( pMDI->DisplayMode != DSP_PAGE )
|
|
{
|
|
pMDI->OldDisplayMode = pMDI->DisplayMode;
|
|
pMDI->DisplayMode = DSP_PAGE;
|
|
AdjustControlSizes ( pDataReq->hwndMDI );
|
|
ShowHideControls ( pDataReq->hwndMDI );
|
|
InitializeMenu ( GetMenu(hwndApp) );
|
|
}
|
|
else // data is for scrolling up or down one page
|
|
{
|
|
SendMessage ( pMDI->hWndListbox, LB_SETCURSEL,
|
|
pDataReq->iListbox, 0L );
|
|
}
|
|
|
|
UpdateNofMStatus ( pDataReq->hwndMDI );
|
|
InvalidateRect ( pDataReq->hwndMDI, NULL, TRUE );
|
|
|
|
// refresh preview bitmap?
|
|
if ( !lpLE->hbmp )
|
|
{
|
|
GetPreviewBitmap ( pDataReq->hwndMDI, lpLE->name,
|
|
pDataReq->iListbox );
|
|
}
|
|
|
|
// PINFO("\r\n");
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
default:
|
|
PERROR (TEXT("unknown type %d in ProcessDataReq\n\r"),
|
|
pDataReq->rqType );
|
|
break;
|
|
}
|
|
|
|
done:
|
|
|
|
SetCursor (hSaveCursor);
|
|
|
|
return bRet;
|
|
}
|