|
|
#include <windows.h>
#include <windowsx.h>
#include <stdarg.h>
#include "common.h"
#include "clipsrv.h"
#include "clipfile.h"
#include "callback.h"
#include "debugout.h"
static HANDLE hmutexClp; // for syncing open and close of clipboard
static BOOL fAnythingToRender = FALSE; static BOOL fService = TRUE; static BOOL fServiceStopped = FALSE; static TCHAR szClass[] = TEXT("ClipSrvWClass"); static TCHAR szServiceName[] = TEXT("Clipbook Service");
static TCHAR wsbuf[128];
DWORD idInst = 0; HINSTANCE hInst; HWND hwndApp; HSZ hszAppName = 0L; TCHAR szTopic[MAX_TOPIC] = TEXT("ClipData"); TCHAR szServer[MAX_TOPIC] = TEXT("ClipSrv"); TCHAR szExec[MAX_EXEC] = TEXT("");
TCHAR szUpdateName[MAX_CLPSHRNAME+1] = TEXT("");
UINT cf_preview; ShrInfo *SIHead = NULL;
static SERVICE_STATUS_HANDLE hService; static SERVICE_STATUS srvstatus = { SERVICE_WIN32_OWN_PROCESS, SERVICE_START_PENDING, SERVICE_ACCEPT_STOP, NO_ERROR, 0L, 1, 200 };
#if DEBUG
HKEY hkeyRoot; HKEY hkeyClp; #endif
void ClipSrvHandler (DWORD);
/////////////////////////////////////////////////////////////////////////
//
// "main" function... just calls StartServiceCtrlDispatcher.
//
/////////////////////////////////////////////////////////////////////////
void _cdecl main( int argc, char **argv) { SERVICE_TABLE_ENTRY srvtabl[] = {{szServiceName, ClipSrvMain}, {NULL, NULL}};
#if DEBUG
DeleteFile("C:\\CLIPSRV.OUT"); #endif
if (argv[1] && !lstrcmpi(argv[1], "-debug")) { fService = FALSE; ClipSrvMain(argc, argv); } else { StartServiceCtrlDispatcher(srvtabl); } }
/*
* ClipSrvMain */
void ClipSrvMain( DWORD argc, LPSTR *argv) { MSG msg;
if (fService) { hService = RegisterServiceCtrlHandler(szServiceName, ClipSrvHandler); }
if (0L != hService || FALSE == fService) { if (fService) { // Tell SCM that we're starting
SetServiceStatus(hService, &srvstatus); }
hInst = GetModuleHandle(TEXT("CLIPSRV.EXE"));
// Perform initializations
if (InitApplication(hInst, &srvstatus)) { if (fService) { // Tell SCM we've started OK
srvstatus.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(hService, &srvstatus);
PINFO(TEXT("Told system we're running\r\n")); }
// Process messages
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
UnregisterClass(szClass, hInst);
if (fService && !fServiceStopped) { fServiceStopped = TRUE; srvstatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hService, &srvstatus); }
if (NULL != hmutexClp) { CloseHandle(hmutexClp); } } else { PERROR(TEXT("ClSrv: InitApplication failed!\r\n")); if (fService && !fServiceStopped) { fServiceStopped = TRUE; srvstatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hService, &srvstatus); } } } }
/*
* ReportStatusToSCMgr * * This function is called by the ServMainFunc() and * by the ServCtrlHandler() to update the service's status * to the Service Control Manager. */
BOOL ReportStatusToSCMgr ( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwCheckPoint, DWORD dwWaitHint) { BOOL fResult;
/* disable control requests until service is started */ if (dwCurrentState == SERVICE_START_PENDING) { srvstatus.dwControlsAccepted = 0; } else { srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; }
/* These SERVICE_STATUS members set from parameters */
srvstatus.dwCurrentState = dwCurrentState; srvstatus.dwWin32ExitCode = dwWin32ExitCode; srvstatus.dwCheckPoint = dwCheckPoint;
srvstatus.dwWaitHint = dwWaitHint;
/* Report status of service to Service Control Manager */
if (!(fResult = SetServiceStatus(hService,&srvstatus))) { /* if error occurs, stop service */ }
return fResult; }
/*
* ClipSrvHandler * * * Purpose: Acts as the HANDLER_FUNCTION for the Clipbook service. * * Parameters: * fdwControl = Flags saying what action to take * * Returns: Void (SetServiceStatus is used to set status) */
void ClipSrvHandler( DWORD fdwControl) {
if (SERVICE_CONTROL_STOP == fdwControl) { PINFO(TEXT("Handler: stopping service\r\n")); srvstatus.dwCheckPoint = 0; srvstatus.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(hService, &srvstatus);
SendMessage(hwndApp, WM_CLOSE, 0, 0);
if (!fServiceStopped) { fServiceStopped = TRUE; srvstatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hService, &srvstatus); } PINFO(TEXT("Handler: Service stopped\r\n")); } else { // Unhandled control request.. just keep running.
srvstatus.dwCurrentState = SERVICE_RUNNING; srvstatus.dwWin32ExitCode = NO_ERROR; SetServiceStatus(hService, &srvstatus); } return;
}
/*
* InitApplication * * * Purpose: Application initialization, including creation of a window * to do DDE with, getting settings out of the registry, and starting * up DDE. * * Parameters: * hInstance - Application instance. * psrvstatus - Pointer to a SERVICE_STATUS struct. We update the * dwCheckPoint member of this struct and call SetServiceStatus, * so the system knows that we didn't die. * * Returns: True on OK, false on fail. */
BOOL InitApplication( HINSTANCE hInstance, SERVICE_STATUS *psrvstatus) { WNDCLASS wc; #if DEBUG
DWORD dwKeyStatus; #endif
HWINSTA hwinsta;
wc.style = 0L; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLIPSRV)); wc.hCursor = NULL; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("ClipSrvWClass");
if (!RegisterClass(&wc)) { PERROR(TEXT("Couldn't register wclass\r\n")); return FALSE; }
/*
* We are now connected to the appropriate service windowstation * and desktop. In order to get stuff from clipbook, we need to * switch our process over to use the interactive user's * clipboard. Verify that we have access to do this. */ hwinsta = OpenWindowStation("WinSta0", FALSE, WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS); if (hwinsta == NULL) { PERROR(TEXT("Couldn't open windowstation WinSta0\r\n")); return FALSE; }
SetProcessWindowStation(hwinsta);
psrvstatus->dwCheckPoint++;
hmutexClp = CreateMutex(NULL, FALSE, SZMUTEXCLP);
hwndApp = CreateWindow(TEXT("ClipSrvWClass"), TEXT("Hidden Data Server"), WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, hInstance, NULL );
if (!hwndApp) { PERROR(TEXT("No window created\r\n")); return FALSE; }
psrvstatus->dwCheckPoint++;
#if DEBUG
if (ERROR_SUCCESS != RegCreateKeyEx (HKEY_CURRENT_USER, szClipviewRoot, 0L, szRegClass, REG_OPTION_NON_VOLATILE, KEY_QUERY_VALUE, NULL, &hkeyClp, &dwKeyStatus) &&
ERROR_SUCCESS != RegOpenKeyEx (HKEY_CURRENT_USER, szClipviewRoot, 0, KEY_QUERY_VALUE, &hkeyClp)) { DebugLevel = 2; PINFO(TEXT("Clipsrv: Could not get root key\r\n")); } else { DWORD iSize = sizeof(DebugLevel);
RegQueryValueEx (hkeyClp, szDebug, NULL, NULL, (LPBYTE)&DebugLevel, &iSize);
RegCloseKey (hkeyClp); }
if (DebugLevel > 0) { ShowWindow(hwndApp, SW_SHOWMINNOACTIVE ); } #endif
if (DdeInitialize ((LPDWORD)&idInst, (PFNCALLBACK)DdeCallback, APPCMD_FILTERINITS, 0L)) { PERROR(TEXT("Couldn't initialize DDE\r\n")); return FALSE; }
PINFO(TEXT("DdeInit OK...\r\n")); psrvstatus->dwCheckPoint++; if (fService) { SetServiceStatus(hService, psrvstatus); }
Hszize(); DdeNameService(idInst, hszAppName, 0L, DNS_REGISTER);
InitShares();
return TRUE; }
/*
* MainWndProc */
LRESULT CALLBACK MainWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) { case WM_CREATE: fAnythingToRender = FALSE; cf_preview = RegisterClipboardFormat (SZPREVNAME);
if (fService) { // Let the SCP that started us know that we're making progress
srvstatus.dwCheckPoint++; SetServiceStatus(hService, &srvstatus); }
PINFO(TEXT("Creating ClSrv window\r\n")); break;
case WM_DESTROYCLIPBOARD: /* Prevent unnecessary file I/O when getting a WM_RENDERALLFORMATS */ fAnythingToRender = FALSE; break;
case WM_RENDERALLFORMATS: PINFO(TEXT("ClSrv\\WM_RNDRALL rcvd\r\n")); return (LRESULT)RenderAllFromFile(szSaveFileName); break;
case WM_RENDERFORMAT: SetClipboardData((UINT)wParam, RenderFormatFromFile(szSaveFileName, (WORD)wParam)); break;
case WM_QUERYOPEN: return FALSE;
case WM_DESTROY: PINFO(TEXT("sTOPPING...\r\n")); CleanUpShares(); DdeNameService(idInst, 0L, 0L, DNS_UNREGISTER); UnHszize(); DdeUninitialize(idInst);
if (fService) { // Tell SCP we're stopping
srvstatus.dwCheckPoint++; SetServiceStatus(hService, &srvstatus); } PostQuitMessage(0); break;
default: return (DefWindowProc(hwnd, message, wParam, lParam)); }
return 0L; }
/*
* RenderRawFormatToDDE */
HDDEDATA RenderRawFormatToDDE( FORMATHEADER *pfmthdr, HANDLE fh ) { HDDEDATA hDDE; LPBYTE lpDDE; DWORD cbData; DWORD dwBytesRead; BOOL fPrivate = FALSE, fMetafile = FALSE, fBitmap = FALSE;
PINFO(TEXT("ClSrv\\RndrRawFmtToDDE:"));
// Note that complex-data formats are sent under a private
// format instead.
if (PRIVATE_FORMAT(pfmthdr->FormatID ) || pfmthdr->FormatID == CF_BITMAP || pfmthdr->FormatID == CF_METAFILEPICT || pfmthdr->FormatID == CF_PALETTE || pfmthdr->FormatID == CF_DIB || pfmthdr->FormatID == CF_ENHMETAFILE ) { fPrivate = TRUE; if (pfmthdr->FormatID == CF_BITMAP) { fBitmap = TRUE; } else if (pfmthdr->FormatID == CF_METAFILEPICT) { fMetafile = TRUE; } pfmthdr->FormatID = RegisterClipboardFormatW(pfmthdr->Name); }
PINFO(TEXT("rendering format %ws as %x\n\r"), (LPTSTR)pfmthdr->Name, pfmthdr->FormatID );
#ifdef CACHEPREVIEWS
if ( pfmthdr->FormatID == cf_preview ) PINFO(TEXT("making APPOWNED data\n\r")); #endif
if (!(hDDE = DdeCreateDataHandle (idInst, NULL, pfmthdr->DataLen, 0L, hszAppName, pfmthdr->FormatID, #ifdef CACHEPREVIEWS
pfmthdr->FormatID == cf_preview ? HDATA_APPOWNED : 0 #else
0 #endif
))) { PERROR(TEXT("Couldn't createdata handle\r\n")); goto done; }
if ( !(lpDDE = DdeAccessData ( hDDE, &cbData )) ) { PERROR(TEXT("Couldn't access handle\r\n")); DdeFreeDataHandle(hDDE); hDDE = 0L; goto done; }
if (~0 == SetFilePointer(fh, pfmthdr->DataOffset, NULL, FILE_BEGIN)) { PERROR(TEXT("Couldn't set file pointer\r\n")); DdeUnaccessData(hDDE); DdeFreeDataHandle(hDDE); hDDE = 0L; goto done; }
ReadFile(fh, lpDDE, pfmthdr->DataLen, &dwBytesRead, NULL);
if (dwBytesRead != pfmthdr->DataLen) { // Error in reading the file
DdeUnaccessData(hDDE); DdeFreeDataHandle(hDDE); PERROR(TEXT("Error reading file: %ld from lread\n\r"), dwBytesRead); hDDE = 0L; goto done; }
// This code packs CF_METAFILEPICT and CF_BITMAP structs to WFW-type
// structs. It may lose extents for very large bitmaps and metafiles
// when going from NT to NT. Main symptom would be "Moved a metafile
// across clipbook and it suddenly grew way outside its bounds".
if (fMetafile) { WIN31METAFILEPICT w31mfp; unsigned uNewSize; HDDEDATA hDDETmp;
uNewSize = pfmthdr->DataLen + sizeof(WIN31METAFILEPICT) - sizeof(METAFILEPICT);
// Have to make a smaller data handle now
hDDETmp = hDDE; hDDE = DdeCreateDataHandle(idInst, NULL, uNewSize, 0L, hszAppName, pfmthdr->FormatID, 0);
w31mfp.mm = (WORD)((METAFILEPICT *)lpDDE)->mm; w31mfp.xExt = (WORD)((METAFILEPICT *)lpDDE)->xExt; w31mfp.yExt = (WORD)((METAFILEPICT *)lpDDE)->yExt;
// Place oldmetafilepict and data in new DDE block
DdeAddData(hDDE, (LPTSTR)&w31mfp, sizeof(WIN31METAFILEPICT), 0L); DdeAddData(hDDE, lpDDE + sizeof(METAFILEPICT), uNewSize - sizeof(WIN31METAFILEPICT), sizeof(WIN31METAFILEPICT));
// Drop old handle
DdeUnaccessData(hDDETmp); DdeFreeDataHandle(hDDETmp);
// We came in with hDDE accessed
lpDDE = DdeAccessData(hDDE, &cbData); } else if (fBitmap) { WIN31BITMAP w31bm; unsigned uNewSize; HDDEDATA hDDETmp;
uNewSize = pfmthdr->DataLen + sizeof(WIN31BITMAP) - sizeof(BITMAP);
// Have to make a smaller data handle now
hDDETmp = hDDE; hDDE = DdeCreateDataHandle(idInst, NULL, uNewSize, 0L, hszAppName, pfmthdr->FormatID, 0);
w31bm.bmType = (WORD)((BITMAP *)lpDDE)->bmType; w31bm.bmWidth = (WORD)((BITMAP *)lpDDE)->bmWidth; w31bm.bmHeight = (WORD)((BITMAP *)lpDDE)->bmHeight; w31bm.bmWidthBytes = (WORD)((BITMAP *)lpDDE)->bmWidthBytes; w31bm.bmPlanes = (BYTE)((BITMAP *)lpDDE)->bmPlanes; w31bm.bmBitsPixel = (BYTE)((BITMAP *)lpDDE)->bmBitsPixel;
// Place old-style bitmap header and data in DDE block
DdeAddData(hDDE, (LPTSTR)&w31bm, sizeof(WIN31BITMAP), 0L); DdeAddData(hDDE, lpDDE + sizeof(BITMAP), uNewSize - sizeof(WIN31BITMAP), sizeof(WIN31BITMAP));
// Drop old handle
DdeUnaccessData(hDDETmp); DdeFreeDataHandle(hDDETmp);
// We came in with hDDE accessed
lpDDE = DdeAccessData(hDDE, &cbData); }
DdeUnaccessData(hDDE);
done: PINFO("Ret %lx\r\n", hDDE); return(hDDE); }
/*
* SyncOpenClipboard */
BOOL SyncOpenClipboard( HWND hwnd) { BOOL fOK;
PINFO(TEXT("\r\nClipSrv: Opening Clipboard\r\n"));
WaitForSingleObject (hmutexClp, INFINITE); fOK = OpenClipboard (hwnd); if (!fOK) { ReleaseMutex (hmutexClp); }
return fOK; }
/*
* SyncCloseClipboard */
BOOL SyncCloseClipboard(void) { BOOL fOK;
PINFO(TEXT("\r\nClipSrv: Closing Clipboard\r\n"));
fOK = CloseClipboard (); ReleaseMutex (hmutexClp);
return fOK; }
|