Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1645 lines
45 KiB

#include <windows.h>
#include <nddeapi.h>
#include <nddesec.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <assert.h>
#include <ddeml.h>
#include <strsafe.h>
#include "common.h"
#include "clipsrv.h"
#include "clipfile.h"
#include "ddeutil.h"
#include "callback.h"
#include "debugout.h"
#define AUTOUPDATE
#define ASKED_FOR_LINK 1
#define ASKED_FOR_OBJECTLINK 2
#define MAX_XERR 128 // maximum number of XERRs we'll store
#define XERR_INUSE 1
typedef struct _XERR // struct for Xaction ERRor
{
HCONV hConv; // the conversation handle
DWORD dwErr; // the error code
DWORD dwUse; // usage, when & with XERR_MASK gives type,
} // bit 1 is set when if struct is in use.
XERR, *PXERR;
XERR gXactErr[MAX_XERR];
TCHAR gszXactErrStr[30];
TCHAR szInitShareCmd[] = SZCMD_INITSHARE;
TCHAR szExitCmd[] = SZCMD_EXIT;
TCHAR szPasteShareCmd[] = SZCMD_PASTESHARE;
TCHAR szDelShareCmd[] = SZCMD_DELETE;
TCHAR szMarkSharedCmd[] = SZCMD_SHARE;
TCHAR szMarkUnSharedCmd[] = SZCMD_UNSHARE;
TCHAR szKeepCmd[] = SZCMD_PASTE;
TCHAR szSaveAsCmd[] = SZCMD_SAVEAS;
TCHAR szSaveAsOldCmd[] = SZCMD_SAVEASOLD;
TCHAR szOpenCmd[] = SZCMD_OPEN;
TCHAR szDebugCmd[] = SZCMD_DEBUG;
TCHAR szVersionCmd[] = SZCMD_VERSION;
TCHAR szSecurityCmd[] = SZCMD_SECURITY;
TCHAR szDebug[] = TEXT("Debug");
TCHAR szVer[] = TEXT("1.1"); // need to be able to
// handle Uni or Ansi req's for this
TCHAR szSection[] = TEXT("Software\\Microsoft\\Clipbook Server");
TCHAR szClipviewRoot[] = TEXT("Software\\Microsoft\\Clipbook");
TCHAR szRegClass[] = TEXT("Config");
HSZ hszSysTopic;
HSZ hszTopicList;
HSZ hszFormatList;
HSZ hszErrorRequest;
/*
* MakeTheRegKey
*
* Purpose: Open the usual key (the one named by szSection) with the
* specified access.
*
* Parameters:
* phkey - Pointer to the HKEY to fill
* regsam - The access types, same as RegCreateKeyEx
*
* Returns:
* ERROR_SUCCESS on success, whatever RegOpenKeyEx returns on fail.
*/
LONG MakeTheRegKey(
PHKEY phkey,
REGSAM regsam)
{
DWORD dwR;
DWORD dwIck;
dwR = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
szSection,
0,
szRegClass,
REG_OPTION_NON_VOLATILE,
regsam,
NULL,
phkey,
&dwIck);
if (dwR == ERROR_SUCCESS)
{
return ERROR_SUCCESS;
}
dwR = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szSection, 0, regsam, phkey);
if (dwR == ERROR_SUCCESS)
{
return ERROR_SUCCESS;
}
PERROR(TEXT("Couldn't regopen %s with %lx access - #%lx\r\n"), szSection, (long)regsam, dwR);
return dwR;
}
/*
* lstrncmp
*/
int lstrncmp(
LPTSTR s1,
LPTSTR s2,
WORD count )
{
unsigned i;
register TCHAR tch1;
register TCHAR tch2;
for (i = 0; i < (unsigned)count; i++)
{
if ( (tch1 = *s1++) != (tch2 = *s2++) )
{
if (tch1 < tch2)
return -1;
else
return 1;
}
}
return 0;
}
/*
* AddXactErr
*
* To add a XERR record for hConv. Called
* when XTYP_CONNECT_CONFIRM.
*/
static VOID AddXactErr(
HCONV hConv)
{
INT i;
for (i=0; i<MAX_XERR; i++)
if (!(gXactErr[i].dwUse & XERR_INUSE))
{
gXactErr[i].hConv = hConv;
gXactErr[i].dwErr = 0;
gXactErr[i].dwUse = XERR_INUSE;
return;
}
}
/*
* DelXactErr
*
* To delete a XERR record for hConv.
* Called at XTYP_DISCONNECT.
*/
static VOID DelXactErr(
HCONV hConv)
{
INT i;
for (i=0; i<MAX_XERR; i++)
if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
{
gXactErr[i].dwUse = 0;
return;
}
}
/*
* GetXactErr
*
* Returns the XERR error code associated with hConv.
*/
DWORD GetXactErr(
HCONV hConv)
{
INT i;
for (i=0; i<MAX_XERR; i++)
if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
return gXactErr[i].dwErr;
return 0L;
}
/*
* GetXactErrType
*
* Returns the XERR error type associated with hConv.
*/
DWORD GetXactErrType(
HCONV hConv)
{
INT i;
for (i=0; i<MAX_XERR; i++)
if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
return gXactErr[i].dwUse & XERRT_MASK;
return 0L;
}
/*
* SetXactErr
*
* Sets XERR for hConv.
* dwType specifies type, this should be one of the XERRT_ defines.
* dwErr specifies error code.
*/
VOID SetXactErr(
HCONV hConv,
DWORD dwType,
DWORD dwErr)
{
INT i;
for (i=0; i<MAX_XERR; i++)
if ((gXactErr[i].dwUse & XERR_INUSE) && gXactErr[i].hConv == hConv)
{
gXactErr[i].dwErr = dwErr;
gXactErr[i].dwUse = (gXactErr[i].dwUse & ~XERRT_MASK) | dwType;
return;
}
}
/*
* DdeCallback
*/
HDDEDATA EXPENTRY DdeCallback(
WORD wType,
WORD wFmt,
HCONV hConv,
HSZ hszTopic,
HSZ hszItem,
HDDEDATA hData,
DWORD lData1,
DWORD lData2)
{
HDDEDATA hDDEtmp = 0L;
UINT uiErr;
PINFO(TEXT("\n>>>> DdeCallback\n"));
if (!(wType & XCLASS_NOTIFICATION))
{
PINFO(TEXT("Impersonating\n"));
DdeImpersonateClient(hConv);
}
switch ( wType )
{
case XTYP_CONNECT_CONFIRM:
PINFO (TEXT("XTYP_CONNECT_CONFIRM\n"));
AddXactErr (hConv);
PINFO(TEXT("Confirming connect\r\n"));
hDDEtmp = (HDDEDATA)TRUE;
break;
case XTYP_EXECUTE:
PINFO (TEXT("XTYP_EXECUTE\n"));
// no error yet
SetXactErr (hConv, 0, 0);
// We only take executes on the System topic.
// And only in Unicode or CF_TEXT format.
if ((wFmt == CF_TEXT || wFmt == CF_UNICODETEXT) &&
DdeCmpStringHandles ( hszTopic, hszSysTopic ) )
{
PERROR(TEXT("XTYP_EXECUTE received on non-system topic\n\r"));
hDDEtmp = (HDDEDATA)DDE_FNOTPROCESSED;
break;
}
DdeGetData(hData, (LPBYTE)szExec, MAX_EXEC, 0);
szExec[MAX_EXEC - 1] = '\0';
hDDEtmp = DDE_FNOTPROCESSED;
if (!lstrcmp (szExec, szInitShareCmd))
{
InitShares();
hDDEtmp = (HDDEDATA)DDE_FACK;
}
else if (!lstrncmp (szExec, szKeepCmd, (WORD)lstrlen(szKeepCmd)))
{
DWORD dwErr;
dwErr = AddShare ( szExec + lstrlen(szKeepCmd ), 0);
if (dwErr != NO_ERROR)
SetXactErr (hConv, XERRT_SYS, dwErr);
else
hDDEtmp = (HDDEDATA)DDE_FACK;
}
else if (!lstrncmp (szExec, szVersionCmd, (WORD)lstrlen(szVersionCmd)))
{
hDDEtmp = DdeCreateDataHandle(idInst, szVer, sizeof(szVer) + 1, 0, 0L, wFmt, 0L);
}
else if (!lstrncmp( szExec, szSaveAsCmd, (WORD)lstrlen(szSaveAsCmd)))
{
DWORD dwErr;
fNTSaveFileFormat = TRUE;
dwErr = SaveClipboardToFile (hwndApp, NULL, szExec + lstrlen(szSaveAsCmd ), FALSE);
if (dwErr != NO_ERROR)
SetXactErr (hConv, XERRT_SYS, dwErr);
else
hDDEtmp = (HDDEDATA)DDE_FACK;
}
else if (!lstrncmp (szExec, szSaveAsOldCmd, (WORD)lstrlen(szSaveAsOldCmd)))
{
DWORD dwErr;
fNTSaveFileFormat = FALSE;
dwErr = SaveClipboardToFile(hwndApp, NULL, szExec + lstrlen(szSaveAsOldCmd), FALSE);
if (dwErr != NO_ERROR)
SetXactErr (hConv, XERRT_SYS, dwErr);
else
hDDEtmp = (HDDEDATA)DDE_FACK;
}
else if (!lstrncmp (szExec, szOpenCmd, (WORD)lstrlen(szOpenCmd )) )
{
DWORD dwErr;
dwErr = OpenClipboardFile(hwndApp, szExec + lstrlen(szOpenCmd));
if (dwErr != NO_ERROR)
SetXactErr (hConv, XERRT_SYS, dwErr);
else
hDDEtmp = (HDDEDATA)DDE_FACK;
}
else if (!lstrncmp (szExec, szDelShareCmd, (WORD)lstrlen(szDelShareCmd)))
{
PINFO(TEXT("Deleting %s\n\r"), (LPSTR)szExec + lstrlen(szDelShareCmd));
if (DelShare ( hConv, szExec + lstrlen(szDelShareCmd) ))
{
hDDEtmp = (HDDEDATA)DDE_FACK;
}
}
else if (!lstrncmp (szExec,szMarkSharedCmd, (WORD)lstrlen(szMarkSharedCmd)))
{
PINFO(TEXT("Marking %s as shared\n\r"), (LPSTR)szExec + lstrlen(szMarkSharedCmd));
if ( MarkShare (szExec + lstrlen(szMarkSharedCmd), SIF_SHARED ))
{
hDDEtmp = (HDDEDATA)DDE_FACK;
}
}
else if (!lstrncmp(szExec,szMarkUnSharedCmd, (WORD)lstrlen(szMarkUnSharedCmd)))
{
if ( MarkShare ( szExec + lstrlen(szMarkUnSharedCmd ), 0 ))
{
hDDEtmp = (HDDEDATA)DDE_FACK;
}
}
#if DEBUG
else if (!lstrncmp(szExec,szDebugCmd, (WORD)lstrlen(szDebugCmd)))
{
DumpShares();
hDDEtmp = (HDDEDATA)DDE_FACK;
}
#endif
else
{
PERROR(TEXT("Invalid execute\r\n"));
hDDEtmp = (HDDEDATA)DDE_FNOTPROCESSED;
}
break;
case XTYP_DISCONNECT:
PINFO (TEXT("XTYP_DISCONNECT\n"));
DelXactErr (hConv);
break;
case XTYP_CONNECT:
PINFO (TEXT("XTYP_CONNECT\n"));
hDDEtmp = (HDDEDATA)FALSE;
if ( IsSupportedTopic( hszTopic ) )
{
if (!DdeKeepStringHandle (idInst, hszAppName))
{
PERROR(TEXT("DdeKSHandle fail in DdeCB\r\n"));
}
hDDEtmp = (HDDEDATA)TRUE;
}
#if DEBUG
else
{
TCHAR buf[128];
DdeQueryString ( idInst, hszTopic, buf, 128, CP_WINANSI );
PERROR(TEXT("ClipSRV: Unsupported topic %s requested\n\r"), (LPSTR)buf );
}
#endif
break;
case XTYP_ADVREQ:
case XTYP_REQUEST:
// must be a valid topic
{
TCHAR atch[128];
PINFO (wType==XTYP_ADVREQ?
TEXT("XTYP_ADVREQ\n"): TEXT("XTYP_REQUEST\n"));
DdeQueryString(idInst, hszTopic, atch, 128, CP_WINANSI);
PINFO(TEXT("Topic = %s, "), atch);
DdeQueryString(idInst, hszItem, atch, 128, CP_WINANSI);
PINFO(TEXT("item = %s\r\n"), atch);
}
if (!IsSupportedTopic ( hszTopic ))
{
#if DEBUG
TCHAR buf[128];
DdeQueryString ( idInst, hszTopic, buf, 128, CP_WINANSI );
PERROR(TEXT("Topic %s unsupported!\n\r"), (LPTSTR)buf );
#endif
hDDEtmp = (HDDEDATA)0;
}
else
{
PINFO("System topic request\r\n");
if (!DdeCmpStringHandles (hszTopic, hszSysTopic))
{
if (!DdeCmpStringHandles (hszItem, hszErrorRequest))
{
StringCchPrintf (gszXactErrStr, 30,
XERR_FORMAT,
GetXactErrType (hConv),
GetXactErr (hConv));
hDDEtmp = DdeCreateDataHandle (idInst,
gszXactErrStr,
lstrlen(gszXactErrStr)+sizeof(CHAR),
0,
hszErrorRequest,
wFmt,
0);
uiErr = DdeGetLastError (idInst);
}
else if (!DdeCmpStringHandles (hszItem, hszTopicList))
{
PINFO(TEXT("Topic list requested\r\n"));
SetXactErr (hConv, 0, 0);
if (CF_TEXT == wFmt)
{
hDDEtmp = (HDDEDATA)GetTopicListA(hConv, TRUE);
}
else if (CF_UNICODETEXT == wFmt)
{
hDDEtmp = (HDDEDATA)GetTopicListW(hConv, TRUE);
}
else // Can't get the topiclist in anything but CF_TEXT or UNICODE
{
PERROR(TEXT("ClSrv\\DdeCB: Client asked for topics in bad fmt\r\n"));
hDDEtmp = (HDDEDATA)0;
}
}
else
{
#if DEBUG
TCHAR rgtch[128];
DdeQueryString(idInst, hszItem,rgtch, 128, CP_WINANSI);
PERROR(TEXT("item %s requested under system\n\r"), rgtch);
#endif
hDDEtmp = (HDDEDATA)0;
}
}
else
{
// all other topics are assumed clipboard shares!!!
// Is format list the requested item?
if (!DdeCmpStringHandles (hszItem, hszErrorRequest))
{
StringCchPrintf (gszXactErrStr, 30,
XERR_FORMAT,
GetXactErrType (hConv),
GetXactErr (hConv));
hDDEtmp = DdeCreateDataHandle (idInst,
gszXactErrStr,
lstrlen(gszXactErrStr)+sizeof(CHAR),
0,
hszErrorRequest,
wFmt,
0);
uiErr = DdeGetLastError (idInst);
}
else if (!DdeCmpStringHandles (hszItem, hszFormatList))
{
PINFO(TEXT("Getting format list\r\n"));
SetXactErr (hConv, 0, 0);
if (CF_TEXT == wFmt)
{
hDDEtmp = (HDDEDATA)GetFormatListA(hConv, hszTopic);
}
else
{
hDDEtmp = (HDDEDATA)GetFormatListW(hConv, hszTopic);
}
}
else
{ // request for specific format, or invalid
SetXactErr (hConv, 0, 0);
hDDEtmp = GetFormat ( hConv, hszTopic, hszItem );
}
}
}
break;
case XTYP_ADVSTART:
PINFO (TEXT("XTYP_ADVSTART\n"));
if (0 == DdeCmpStringHandles(hszItem, hszTopicList) &&
0 == DdeCmpStringHandles(hszTopic, hszSysTopic))
{
PINFO(TEXT("Advise on topiclist OK\r\n"));
hDDEtmp = (HDDEDATA)TRUE;
}
else
{
PERROR(TEXT("Advise loop requested on item other than topiclist\n\r"));
hDDEtmp = (HDDEDATA)FALSE;
}
break;
default:
PINFO (TEXT("unknown wType %#x\n"), wType);
break;
}
if (!(wType & XCLASS_NOTIFICATION))
{
RevertToSelf();
}
if (0L == hDDEtmp)
{
TCHAR atch[128];
DdeQueryString(idInst, hszTopic, atch, 128, CP_WINANSI);
PINFO(TEXT("Topic was %s, "), atch);
DdeQueryString(idInst, hszItem, atch, 128, CP_WINANSI);
PINFO(TEXT("item was %s\r\n"), atch);
}
PINFO(TEXT("Return %#x\n"), hDDEtmp);
PINFO(TEXT("<<<< DdeCallback\n\n"));
return hDDEtmp;
}
/*
* IsSupportedTopic
*/
BOOL IsSupportedTopic ( HSZ hszTopic )
{
pShrInfo p;
if ( !DdeCmpStringHandles (hszTopic, hszSysTopic))
{
DdeKeepStringHandle ( idInst, hszTopic );
return TRUE;
}
for ( p = SIHead; p; p = p->Next )
{
if (!DdeCmpStringHandles (hszTopic, p->hszName))
return TRUE;
}
return FALSE;
}
/*
* CleanUpShares
*/
BOOL CleanUpShares ( VOID )
{
pShrInfo p, tmp;
for (p=SIHead; p; p=tmp)
{
DdeFreeStringHandle ( idInst, p->hszName );
#ifdef CACHEFORMATLIST
PINFO(TEXT("freeing cached format list\n\r"));
if ( p->hFormatList )
DdeFreeDataHandle ( p->hFormatList );
#endif
#ifdef CACHEPREVIEWS
PINFO(TEXT("freeing cached preview bitmap\n\r"));
if ( p->hPreviewBmp )
DdeFreeDataHandle ( p->hPreviewBmp );
#endif
tmp = p->Next;
LocalFree ((HLOCAL) p );
}
SIHead = NULL;
return TRUE;
}
/*
* InitShares
*/
BOOL InitShares (VOID)
{
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+3];
TCHAR rgtchPageName[MAX_CLPSHRNAME+1];
TCHAR rgtchPageFile[MAX_FILEPATH+1];
DWORD dwPageSize;
DWORD dwNameSize;
DWORD dwType;
HKEY hkeyClp;
DWORD dwR;
unsigned iValue = 0;
unsigned iKeys = 0;
CleanUpShares ();
if (ERROR_SUCCESS != MakeTheRegKey(&hkeyClp, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE))
{
PERROR(TEXT("Couldn't get to Clipbook root key\r\n"));
return FALSE;
}
szComputerName[0] = szComputerName[1] = TEXT('\\');
dwNameSize = MAX_COMPUTERNAME_LENGTH+1;
GetComputerName (szComputerName+2, &dwNameSize);
do {
dwNameSize = sizeof (rgtchPageName);
dwPageSize = sizeof (rgtchPageFile);
dwR = RegEnumValue (hkeyClp,
iValue,
rgtchPageName,
&dwNameSize,
NULL,
&dwType,
(LPBYTE)rgtchPageFile,
&dwPageSize);
if (dwR == ERROR_SUCCESS)
{
rgtchPageName[dwNameSize] = 0;
rgtchPageFile[dwPageSize] = 0;
AddRecord (rgtchPageName,
rgtchPageFile,
(SHR_CHAR == rgtchPageName[0]) ? SIF_SHARED : 0);
}
iValue++;
} while (dwR != ERROR_NO_MORE_ITEMS);
RegCloseKey(hkeyClp);
PINFO(TEXT("Read %d pages\r\n"),iKeys);
return TRUE;
}
/*
* GetFormat
*/
HDDEDATA GetFormat (
HCONV hConv,
HSZ hszTopic,
HSZ hszItem )
{
HDDEDATA hData = 0l;
HANDLE hClpData = NULL;
DWORD cbData = 0L;
pShrInfo pshrinfo;
HANDLE fh;
FORMATHEADER FormatHeader;
unsigned i;
TCHAR szItemKey[CCHFMTNAMEMAX];
unsigned cFormats;
BOOL fPreviewRequested;
unsigned fLocalAskedForLocal = 0;
#ifndef UNICODE
TCHAR szFormatName[CCHFMTNAMEMAX * 2];
#endif
PINFO(TEXT("Clsrv\\GetFormat:"));
if (!DdeQueryString (idInst,hszItem,szItemKey,CCHFMTNAMEMAX,CP_WINANSI))
{
PERROR(TEXT("invalid item\n\r"));
return 0;
}
// is the asked-for format cf_preview?
fPreviewRequested = !lstrcmpi ( szItemKey, SZPREVNAME );
for ( pshrinfo=SIHead; pshrinfo; pshrinfo = pshrinfo->Next )
{
if ( DdeCmpStringHandles ( hszTopic, pshrinfo->hszName ) == 0 )
{
DdeKeepStringHandle ( idInst, hszTopic );
if ( fPreviewRequested && pshrinfo->hPreviewBmp )
{
return pshrinfo->hPreviewBmp;
}
fh = CreateFileW(pshrinfo->szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if ( INVALID_HANDLE_VALUE == fh)
{
PERROR(TEXT("ERROR opening %ls\n\r"), pshrinfo->szFileName );
}
else
{
cFormats = ReadFileHeader(fh);
if (0 == cFormats)
{
PERROR(TEXT("Bad .CLP file\r\n"));
}
for (i=0; i < cFormats; i++)
{
ReadFormatHeader(fh, &FormatHeader, i);
#ifndef UNICODE
WideCharToMultiByte (CP_ACP,
0,
FormatHeader.Name,
CCHFMTNAMEMAX,
szFormatName,
CCHFMTNAMEMAX * 2,
NULL,
NULL);
if (!lstrcmpi (szItemKey, szFormatName))
#else
if (!lstrcmpi (szItemKey, FormatHeader.Name))
#endif
{
// Put back the format names, if a local client asked
// us for objectlink or link.
if (ASKED_FOR_OBJECTLINK == fLocalAskedForLocal)
{
StringCchCopyW(FormatHeader.Name, CCHFMTNAMEMAX, LSZOBJECTLINK);
}
else if (ASKED_FOR_LINK == fLocalAskedForLocal)
{
StringCchCopyW(FormatHeader.Name, CCHFMTNAMEMAX, LSZLINK);
}
hData = RenderRawFormatToDDE(&FormatHeader, fh);
#ifdef CACHEPREVIEWS
if ( fPreviewRequested )
{
PINFO(TEXT("GetFormat: caching preview\n\r"));
pshrinfo->hPreviewBmp = hData;
}
#endif
#if DEBUG
if (!hData)
{
PERROR(TEXT("RenderRawFormatToDDE resulted in 0 handle\n\r"));
}
#endif
}
}
if (!hData)
{
PERROR(TEXT("GetFormat: requested format %s not found\n\r"),
(LPSTR)szItemKey );
}
CloseHandle(fh);
}
}
}
PINFO("Returning %lx",hData);
return hData;
}
/*
* DelShare
*
* Purpose: Delete a ClipBook page.
*
* Parameters:
* pszName - The name of the page.
*
* Returns:
* TRUE on success, FALSE on failure.
*/
BOOL DelShare(
HCONV hConv,
TCHAR *pszName)
{
pShrInfo pshrinfo;
pShrInfo q;
HKEY hkeyClp;
TCHAR atch[MAX_COMPUTERNAME_LENGTH + 3];
DWORD dwLen = MAX_COMPUTERNAME_LENGTH + 1;
BOOL fOK = FALSE;
DWORD ret;
WCHAR rgwchT[MAX_CLPSHRNAME + 1];
TCHAR tch;
assert(pszName);
assert(*pszName);
#ifndef UNICODE
MultiByteToWideChar(CP_ACP, 0, pszName, -1, rgwchT, MAX_CLPSHRNAME + 1);
#else
StringCchCopy(rgwchT, MAX_CLPSHRNAME + 1, pszName);
#endif
PINFO(TEXT("Looking for %ls\r\n"), rgwchT);
q = NULL;
for (pshrinfo = SIHead; pshrinfo; pshrinfo = (q = pshrinfo)->Next)
{
assert(pshrinfo->szName);
PINFO(TEXT("Comparing to %ls\r\n"), pshrinfo->szName);
if (!lstrcmpW(pshrinfo->szName, rgwchT))
{
// Delete the Network DDE share for this item
atch[0] = atch[1] = TEXT('\\');
dwLen = MAX_COMPUTERNAME_LENGTH +1;
GetComputerName(atch+2, &dwLen);
tch = pszName[0];
pszName[0] = SHR_CHAR;
PINFO(TEXT("Deleting share %s on %s\r\n"), pszName, atch);
ret = NDdeShareDel(atch, pszName, 0);
pszName[0] = tch;
if (NDDE_NO_ERROR == ret)
{
// Delete the key in the registry
RevertToSelf();
if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
{
RegDeleteValue(hkeyClp, pszName);
RegCloseKey(hkeyClp);
}
else
{
PERROR(TEXT("Couldn't delete key! #%ld\r\n"), GetLastError());
}
DdeImpersonateClient(hConv);
// force render all if applicable!
SendMessage (hwndApp, WM_RENDERALLFORMATS, 0, 0L);
// unlink file!
DeleteFileW(pshrinfo->szFileName);
// Take this page out of the linked list of pages.
if (q == NULL)
{
SIHead = pshrinfo->Next;
}
else
{
q->Next = pshrinfo->Next;
}
DdeFreeStringHandle ( idInst, pshrinfo->hszName );
if ( pshrinfo->hFormatList )
DdeFreeDataHandle ( pshrinfo->hFormatList );
if ( pshrinfo->hPreviewBmp )
DdeFreeDataHandle ( pshrinfo->hPreviewBmp );
LocalFree ( (HLOCAL)pshrinfo );
#ifdef AUTOUPDATE
DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
#endif
fOK = TRUE;
}
else
{
PERROR(TEXT("Csrv: NDde err %ld on delshare\r\n"), ret);
SetXactErr (hConv, XERRT_NDDE, ret);
}
break; // Don't loop thru additional pages if you found the right one
}
}
if (!fOK)
{
PERROR(TEXT("Clipsrv: item to delete '%s' not found\n\r"), pszName );
}
return fOK;
}
/*
* AddRecord
*
* Purpose:
* Add a record to the linked list of Clipbook pages in memory.
*
* Parameters:
* lpszName - Name of the page.
* lpszFileName - Name of the .CLP file containing the page's data.
* siflags - Flags for the page.
*
* Returns:
* TRUE on success, FALSE on failure
*/
BOOL AddRecord (
LPTSTR lpszName,
LPTSTR lpszFileName,
ULONG siflags)
{
pShrInfo pshrinfo;
PINFO(TEXT("Making page %s with file %s\r\n"), lpszName, lpszFileName);
pshrinfo = (pShrInfo) LocalAlloc ( LPTR, sizeof ( ShrInfo ) );
if ( !pshrinfo )
{
PERROR(TEXT("AddRecord: LocalAlloc failed\n\r"));
return FALSE;
}
if ( !( pshrinfo->hszName = DdeCreateStringHandle ( idInst, lpszName, 0 )))
{
PERROR(TEXT("AddRecord: DdeCHSZ fail\r\n"));
LocalFree (pshrinfo);
return(FALSE);
}
#ifdef UNICODE
StringCchCopy( pshrinfo->szFileName, MAX_FILEPATH, lpszFileName );
StringCchCopy( pshrinfo->szName, MAX_CLPSHRNAME+1, lpszName );
#else
MultiByteToWideChar(CP_ACP, 0L, lpszFileName, -1, pshrinfo->szFileName, MAX_FILEPATH - 1);
MultiByteToWideChar(CP_ACP, 0L, lpszName, -1, pshrinfo->szName, MAX_CLPSHRNAME);
#endif
PINFO(TEXT("Made page %ls with file %ls\r\n"), pshrinfo->szName, pshrinfo->szFileName);
#ifdef CACHEFORMATLIST
pshrinfo->hFormatList = 0L;
#endif
#ifdef CACHEPREVIEWS
pshrinfo->hPreviewBmp = 0L;
#endif
pshrinfo->Next = SIHead;
SIHead = pshrinfo;
pshrinfo->flags = (WORD) siflags;
return TRUE;
}
/*
* ResetRecord
*
* When paste into an existing page, we need to clear the cached
* stuff for the old data.
*/
void ResetRecord (pShrInfo pInfo)
{
// clear the format list
if (pInfo->hFormatList)
{
DdeFreeDataHandle (pInfo->hFormatList);
pInfo->hFormatList = NULL;
}
// clear the preview bitmap
if (pInfo->hPreviewBmp)
{
DdeFreeDataHandle (pInfo->hPreviewBmp);
pInfo->hPreviewBmp = NULL;
}
}
/*
* GetShareFileName
*
*/
pShrInfo GetShareFileName (LPTSTR szSName, LPTSTR szFName)
{
BOOL bRet = FALSE;
HSZ hS;
CHAR cSave;
pShrInfo pInfo;
cSave = *szSName;
hS = DdeCreateStringHandle (idInst, szSName, 0);
if (!hS)
goto done;
for (pInfo = SIHead; pInfo; pInfo = pInfo->Next)
if (!DdeCmpStringHandles (pInfo->hszName, hS))
{
#ifndef UNICODE
WideCharToMultiByte (CP_ACP,
0,
pInfo->szFileName,
-1,
szFName,
MAX_PATH+1,
NULL,
NULL);
#else
StringCchCopy (szFName, MAX_PATH+1, pInfo->szFileName);
#endif
bRet = TRUE;
goto done;
}
DdeFreeStringHandle (idInst, hS);
// not found, change share name to shared or unshared
if (UNSHR_CHAR == cSave)
*szSName = SHR_CHAR;
else
*szSName = UNSHR_CHAR;
// try again with new share name
hS = DdeCreateStringHandle (idInst, szSName, 0);
if (!hS)
goto done;
for (pInfo = SIHead; pInfo; pInfo = pInfo->Next)
if (!DdeCmpStringHandles (pInfo->hszName, hS))
{
#ifndef UNICODE
WideCharToMultiByte (CP_ACP,
0,
pInfo->szFileName,
-1,
szFName,
MAX_PATH+1,
NULL,
NULL);
#else
StringCchCopy (szFName, MAX_PATH+1, pInfo->szFileName);
#endif
bRet = TRUE;
goto done;
}
done:
if (hS)
DdeFreeStringHandle (idInst, hS);
*szSName = cSave;
if (bRet)
return pInfo;
else
return NULL;
}
/*
* AddShare
*
* Purpose:
* Creates a new Clipbook page by doing this:
* - Save the current clipboard with some random file name.
* - Add the Clipbook page to the list in memory
* - Record the existence of the page in the Clipbook Server
* section of the registry. The value name is the page name,
* and the value is the filename.
*
* Parameters:
* pszName - Name of the page.
* flags - Flags to store with the page.
*
* Returns:
* TRUE on success, FALSE on failure.
*/
DWORD AddShare(
LPTSTR pszName,
WORD flags)
{
TCHAR szFName[MAX_PATH+1];
HKEY hkeyClp;
DWORD dwR = NO_ERROR;
pShrInfo pInfo;
fNTSaveFileFormat = TRUE;
if (pInfo = GetShareFileName (pszName, szFName))
{
dwR = SaveClipboardToFile (hwndApp, pszName, szFName, TRUE);
ResetRecord (pInfo);
StringCchCopy (szUpdateName, MAX_CLPSHRNAME+1, pszName);
}
else
{
dwR = GetRandShareFileName (szFName);
if (dwR != NO_ERROR)
return dwR;
dwR = SaveClipboardToFile (hwndApp, pszName, szFName, TRUE);
if (dwR != NO_ERROR)
return dwR;
if (!AddRecord ( pszName, szFName, flags ))
return ERROR_NOT_ENOUGH_MEMORY;
if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
{
RegSetValueEx(hkeyClp, pszName, 0, REG_SZ, szFName, lstrlen(szFName));
RegCloseKey(hkeyClp);
PINFO(TEXT("%s is being written...\n\r"), pszName);
}
}
#ifdef AUTOUPDATE
DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
#endif
return dwR;
}
#if DEBUG
/*
* DumpShares
*/
VOID DumpShares (void)
{
char buf[65];
pShrInfo pshrinfo;
int i;
DWORD cbRet;
for ( i=0, pshrinfo = SIHead; pshrinfo; pshrinfo = pshrinfo->Next, i++ )
{
PINFO(TEXT("---------- Share %d flags:%x-------------\n\r"), i, pshrinfo->flags );
cbRet = DdeQueryString ( idInst, pshrinfo->hszName, buf, 128L, CP_WINANSI );
PINFO(TEXT("name: >%s<\n\r"), (LPSTR)pshrinfo->szName );
PINFO(TEXT("hsz: >%s<\n\r"), cbRet? (LPSTR)buf : (LPSTR)TEXT("ERROR") );
}
}
#else
VOID DumpShares (void)
{
}
#endif
/*
* MarkShare
*
* Purpose: Mark a Clipbook page as shared or unshared.
*
* Parameters:
* pszName - Name of the page.
* flags - 0 for "unshared", SIF_SHARED for "shared."
*
* Returns:
* TRUE on success, FALSE on failure.
*
*/
BOOL MarkShare(
TCHAR *pszName,
WORD flags)
{
PSECURITY_DESCRIPTOR pSDShare;
pShrInfo pshrinfo;
HKEY hkeyClp;
INT iTmp;
ACCESS_ALLOWED_ACE *pace;
WCHAR rgwchT[MAX_CLPSHRNAME+1];
UINT ret;
DWORD dwBytes = sizeof(pSDShare);
WORD wItems = 0;
PACL Acl;
BOOL fDacl;
BOOL fDefault;
DWORD i;
#ifndef UNICODE
MultiByteToWideChar(CP_ACP, 0, pszName, -1, rgwchT, MAX_CLPSHRNAME);
#endif
PINFO(TEXT("Entering MarkShare\r\n"));
for (pshrinfo = SIHead; pshrinfo; pshrinfo = pshrinfo->Next)
{
#ifdef UNICODE
iTmp = lstrcmpW (pshrinfo->szName+1, pszName+1);
#else
iTmp = lstrcmpW (pshrinfo->szName+1, rgwchT+1);
#endif
if (!iTmp)
{
PINFO(TEXT("MarkShare: marking %s %d\n\r"), (LPSTR)pszName, flags );
// If the name's changing, need to delete old reg key.
// (We make the new one after hitting the file security.)
if ((pshrinfo->flags & SIF_SHARED) != (flags & SIF_SHARED))
{
PINFO(TEXT("Changing shared status\r\n"));
// Delete the registry item with the old name
if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
{
PINFO(TEXT("Deleting old name %ws\r\n"),pshrinfo->szName);
RegDeleteValueW(hkeyClp, pshrinfo->szName);
RegCloseKey(hkeyClp);
}
else
{
PERROR(TEXT("MarkShare: Couldn't open registry!\r\n"));
}
}
// Set name to reflect shared/unshared status
pshrinfo->szName[0] = (flags & SIF_SHARED) ? SHR_CHAR : UNSHR_CHAR;
pshrinfo->flags = flags;
// Sync the security on the Clipbook page file to be
// analogous to the security set on the NetDDE share.
pszName[0] = SHR_CHAR;
NDdeGetShareSecurity(NULL, pszName, DACL_SECURITY_INFORMATION, NULL, 0, &i);
PINFO(TEXT("Getting security %ld bytes\r\n"), i);
if (!(pSDShare = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, i)))
{
PERROR(TEXT("LocalAlloc fail\r\n"));
}
else
{
ret = NDdeGetShareSecurity (NULL,
pszName,
DACL_SECURITY_INFORMATION,
pSDShare,
i,
&i);
if (NDDE_NO_ERROR != ret)
{
PERROR(TEXT("Couldn't get sec #%ld\r\n"), ret);
}
else if (!GetSecurityDescriptorDacl(pSDShare, &fDacl, &Acl, &fDefault))
{
PERROR(TEXT("GetDACL fail %ld\r\n"), GetLastError());
}
else
{
DWORD dwGeneric;
for (i = 0; GetAce(Acl, i, &pace); i++)
{
dwGeneric = 0L;
// Convert NDDE access mask types to generic access
// mask types
if (ACCESS_ALLOWED_ACE_TYPE == pace->Header.AceType ||
ACCESS_DENIED_ACE_TYPE == pace->Header.AceType)
{
if ((pace->Mask & NDDE_SHARE_READ) == NDDE_SHARE_READ)
{
PINFO(TEXT("R"));
dwGeneric |= GENERIC_READ;
}
if ((pace->Mask & NDDE_SHARE_WRITE) == NDDE_SHARE_WRITE)
{
PINFO(TEXT("R"));
dwGeneric |= GENERIC_WRITE;
}
if ((pace->Mask & NDDE_GUI_CHANGE) == NDDE_GUI_CHANGE)
{
PINFO(TEXT("D"));
dwGeneric |= GENERIC_WRITE|GENERIC_READ|DELETE;
}
if ((pace->Mask & NDDE_GUI_FULL_CONTROL) ==
NDDE_GUI_FULL_CONTROL)
{
PINFO(TEXT("A"));
dwGeneric |= GENERIC_ALL;
}
PINFO(TEXT(" = %ld\r\n"), dwGeneric);
pace->Mask = dwGeneric;
}
else
{
PERROR(TEXT("Invalid ACE type!!!\r\n"));
}
}
ret = SetFileSecurityW (pshrinfo->szFileName,
DACL_SECURITY_INFORMATION,
pSDShare);
if (FALSE == ret)
{
PERROR(TEXT("SetFSec err %ld\r\n"), GetLastError());
}
}
LocalFree(pSDShare);
}
DdeFreeStringHandle ( idInst, pshrinfo->hszName );
pshrinfo->hszName = DdeCreateStringHandleW( idInst, pshrinfo->szName,
CP_WINUNICODE);
if ( !pshrinfo->hszName )
{
PERROR(TEXT("DdeCreateStringHandle failed\n\r"));
}
else
{
// update the registry to show shared/unshared status
if (ERROR_SUCCESS == MakeTheRegKey(&hkeyClp, KEY_SET_VALUE))
{
PINFO(TEXT("Making registry key %ls from %ls, %d\r\n"),
pshrinfo->szName, pshrinfo->szFileName,
lstrlenW(pshrinfo->szFileName));
RegSetValueExW (hkeyClp,
pshrinfo->szName,
0,
REG_SZ,
(LPBYTE)pshrinfo->szFileName,
lstrlenW (pshrinfo->szFileName) *sizeof(WCHAR) +sizeof(WCHAR));
RegCloseKey(hkeyClp);
DdePostAdvise ( idInst, hszSysTopic, hszTopicList );
return TRUE;
}
else
{
PERROR(TEXT("Could not make registry key to record %s"),
pshrinfo->szName);
}
}
}
}
PERROR(TEXT("Item to mark '%s' not found\n\r"), pszName );
return FALSE;
}
/*
* Hszize
* This creates often used global hszs from standard global strings.
* It also fills the hsz fields of the topic and item tables.
*
*/
void Hszize(void)
{
hszAppName = DdeCreateStringHandle (idInst, szServer, 0L);
hszSysTopic = DdeCreateStringHandle (idInst, SZDDESYS_TOPIC, 0L);
hszTopicList = DdeCreateStringHandle (idInst, SZDDESYS_ITEM_TOPICS, 0L);
hszFormatList = DdeCreateStringHandle (idInst, SZ_FORMAT_LIST, 0L);
hszErrorRequest = DdeCreateStringHandle (idInst, SZ_ERR_REQUEST, 0L);
#ifdef DEBUG
if ( !hszAppName || !hszSysTopic || !hszTopicList || !hszFormatList )
{
PERROR(TEXT("error creating HSZ constants\n\r"));
}
#endif
}
/*
* UnHszize
*/
void UnHszize(void)
{
DdeFreeStringHandle (idInst, hszAppName);
DdeFreeStringHandle (idInst, hszSysTopic);
DdeFreeStringHandle (idInst, hszTopicList);
DdeFreeStringHandle (idInst, hszFormatList);
DdeFreeStringHandle (idInst, hszErrorRequest);
}
/*
* GetRandShareFileName
*
* Purpose:
* Generate a random share file name in the Windows directory.
*
* Parameters:
* buf - Buffer to place the file name in.
*
* Returns:
* TRUE if a valid filename was found, or FALSE if all of the random
* filenames are taken up.
*/
DWORD GetRandShareFileName (
LPTSTR buf)
{
TCHAR szWinDir[144];
BOOL IsUnique = FALSE;
WORD rand;
WORD cTry = 0;
HANDLE hFile;
if (!GetWindowsDirectory( szWinDir, 144))
{
return GetLastError();
}
rand = (WORD)GetTickCount() % 10000;
do {
StringCchPrintf ( buf, MAX_PATH+1, TEXT("%s\\CBK%04d.CLP"), szWinDir, rand++ );
hFile = CreateFile (buf,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
}while (INVALID_HANDLE_VALUE == hFile && cTry++ < 10000);
if (INVALID_HANDLE_VALUE == hFile)
{
PERROR(TEXT("GetRandShareFileName: More than 10000 clipbook file exist!\r\n"));
return GetLastError();
}
else
{
CloseHandle(hFile);
return NO_ERROR;
}
}