CVS: seamlessrdp/ClientDLL Client.Reg,NONE,1.1 StdString.h,NONE,1.1 TSWindowClipper.vcproj,NONE,1.1 Tokenizer.cpp,NONE,1.1 Tokenizer.h,NONE,1.1 WindowData.cpp,NONE,1.1 WindowData.h,NONE,1.1 clipper.Def,NONE,1.1 clipper.cpp,NONE,1.1 clipper.h,NONE,1.1 hash.cpp,NONE,1.1 hash.h,NONE,1.1
Peter Åstrand <[email protected]>
| Newsgroups | gmane.network.rdesktop.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/rdesktop/seamlessrdp/ClientDLL
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1824/ClientDLL
Added Files:
Client.Reg StdString.h TSWindowClipper.vcproj Tokenizer.cpp
Tokenizer.h WindowData.cpp WindowData.h clipper.Def
clipper.cpp clipper.h hash.cpp hash.h
Log Message:
Imported CodeProject tswindowclipper source.
--- NEW FILE: Client.Reg ---
REGEDIT4
[HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\TSWindowClipper]
"Name" = "TSWindowClipper.dll"
--- NEW FILE: StdString.h ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: TSWindowClipper.vcproj ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: Tokenizer.cpp ---
/////////////////////////////////////////////////////////////////////////////
// Tokenizer.cpp
//
// Date: Thursday, November 18, 1999
// Autor: Eduardo Velasquez
// Description: Tokenizer class for CStrings. Works like strtok().
///////////////
//#include "atlstr.h"
#include "Tokenizer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CTokenizer::CTokenizer(const CStdString& cs, const CStdString& csDelim):
m_cs(cs),
m_nCurPos(0)
{
SetDelimiters(csDelim);
}
void CTokenizer::SetDelimiters(const CStdString& csDelim)
{
for(int i = 0; i < csDelim.GetLength(); ++i)
m_delim.set(static_cast<BYTE>(csDelim[i]));
}
bool CTokenizer::Next(CStdString& cs)
{
cs.Empty();
while(m_nCurPos < m_cs.GetLength() && m_delim[static_cast<BYTE>(m_cs[m_nCurPos])])
++m_nCurPos;
if(m_nCurPos >= m_cs.GetLength())
return false;
int nStartPos = m_nCurPos;
while(m_nCurPos < m_cs.GetLength() && !m_delim[static_cast<BYTE>(m_cs[m_nCurPos])])
++m_nCurPos;
cs = m_cs.Mid(nStartPos, m_nCurPos - nStartPos);
return true;
}
CStdString CTokenizer::Tail() const
{
int nCurPos = m_nCurPos;
while(nCurPos < m_cs.GetLength() && m_delim[static_cast<BYTE>(m_cs[nCurPos])])
++nCurPos;
CStdString csResult;
if(nCurPos < m_cs.GetLength())
csResult = m_cs.Mid(nCurPos);
return csResult;
}
--- NEW FILE: Tokenizer.h ---
/////////////////////////////////////////////////////////////////////////////
// Tokenizer.h
//
// Date: Monday, October 22, 2001
// Autor: Eduardo Velasquez
// Description: Tokenizer class for CStrings. Works like strtok.
///////////////
#include "StdString.h"
#if !defined(__TOKENIZER_H__)
#define __TOKENIZER_H__
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#if !defined(_BITSET_)
# include <bitset>
#endif // !defined(_BITSET_)
class CTokenizer
{
public:
CTokenizer(const CStdString& cs, const CStdString& csDelim);
void SetDelimiters(const CStdString& csDelim);
bool Next(CStdString& cs);
CStdString Tail() const;
private:
CStdString m_cs;
std::bitset<256> m_delim;
int m_nCurPos;
};
#endif // !defined(__TOKENIZER_H__)
--- NEW FILE: WindowData.cpp ---
//*********************************************************************************
//
//Title: Terminal Services Window Clipper
//
//Author: Martin Wickett
//
//Date: 2004
//
//*********************************************************************************
#include "WindowData.h"
CWindowData::CWindowData(const CStdString& csId) : m_csTitle(""),m_csId(""), m_iX1(0),m_iY1(0),m_iX2(0),m_iY2(0)
{
}
void CWindowData::SetId(const CStdString& csId)
{
m_csId = csId;
}
void CWindowData::SetTitle(const CStdString& csTitle)
{
m_csTitle = csTitle;
}
void CWindowData::SetX1(int iX1)
{
m_iX1 = iX1;
}
void CWindowData::SetY1(int iY1)
{
m_iY1 = iY1;
}
void CWindowData::SetX2(int iX2)
{
m_iX2 = iX2;
}
void CWindowData::SetY2(int iY2)
{
m_iY2 = iY2;
}
CStdString CWindowData::GetId()
{
return this->m_csId;
}
CStdString CWindowData::GetTitle()
{
return this->m_csTitle;
}
int CWindowData::GetX1()
{
return this->m_iX1;
}
int CWindowData::GetY1()
{
return this->m_iY1;
}
int CWindowData::GetX2()
{
return this->m_iX2;
}
int CWindowData::GetY2()
{
return this->m_iY2;
}
--- NEW FILE: WindowData.h ---
//*********************************************************************************
//
//Title: Terminal Services Window Clipper
//
//Author: Martin Wickett
//
//Date: 2004
//
//*********************************************************************************
#include "StdString.h"
#if !defined(__WINDOWDATA_H__)
#define __WINDOWDATA_H__
class CWindowData
{
public:
CWindowData(const CStdString& csId);
void CWindowData::SetId(const CStdString& csId);
void CWindowData::SetTitle(const CStdString& csTitle);
void CWindowData::SetX1(int iX1);
void CWindowData::SetY1(int iY1);
void CWindowData::SetX2(int iX2);
void CWindowData::SetY2(int iY2);
HWND CWindowData::TaskbarWindowHandle;
CStdString CWindowData::GetId();
CStdString CWindowData::GetTitle();
int CWindowData::GetX1();
int CWindowData::GetY1();
int CWindowData::GetX2();
int CWindowData::GetY2();
private:
CStdString m_csTitle;
CStdString m_csId;
int m_iX1,m_iY1,m_iX2,m_iY2;
};
#endif // !defined(__WINDOWDATA_H__)
--- NEW FILE: clipper.Def ---
LIBRARY TSWindowClipper
EXPORTS
VirtualChannelEntry @1
--- NEW FILE: clipper.cpp ---
//*********************************************************************************
//
//Title: Terminal Services Window Clipper
//
//Author: Martin Wickett
//
//Date: 2004
//
//*********************************************************************************
#define TSDLL
#include "clipper.h"
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
UNREFERENCED_PARAMETER(lpvReserved);
UNREFERENCED_PARAMETER(hinstDLL);
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
void WINAPI VirtualChannelOpenEvent(DWORD openHandle, UINT event, LPVOID pdata,
UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags)
{
LPDWORD pdwControlCode = (LPDWORD)pdata;
CHAR ourData[1600];
UINT ui = 0;
UNREFERENCED_PARAMETER(openHandle);
UNREFERENCED_PARAMETER(dataFlags);
ZeroMemory(ourData, sizeof(ourData));
//copy the send string (with the same lenth of the data)
strncpy(ourData,(LPSTR)pdata,dataLength/sizeof(char));
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Virtual channel data received");
OutputDebugString(ourData);
}
if (dataLength == totalLength)
{
switch(event)
{
case CHANNEL_EVENT_DATA_RECEIVED:
{
CTokenizer tok(_T((LPSTR)ourData), _T(";"));
CStdString cs;
CWindowData* wid=new CWindowData("");
CStdString messageType;
int mixMaxType = 0;
while(tok.Next(cs))
{
CStdString msg;
CTokenizer msgTok(cs, _T("="));
msgTok.Next(msg);
if (strcmp(msg,"MSG")==0)
{
msgTok.Next(msg);
messageType = msg;
}
if (strcmp(msg,"ID")==0)
{
msgTok.Next(msg);
wid->SetId(msg);
}
else if (strcmp(msg,"TITLE")==0)
{
msgTok.Next(msg);
wid->SetTitle(msg);
}
else if (strcmp(msg,"POS")==0)
{
msgTok.Next(msg);
CStdString pos;
CTokenizer posTok(msg, _T("~"));
posTok.Next(pos);
// check bounds, coords can be negative if window top left point is moved off the screen.
// we don't care about that since the window can't be see so just use zero.
if (strchr(pos, '-')==NULL)
{
wid->SetX1(atoi(pos));
}
else
{
wid->SetX1(0);
}
posTok.Next(pos);
if (strchr(pos, '-')==NULL)
{
wid->SetY1(atoi(pos));
}
else
{
wid->SetY1(0);
}
posTok.Next(pos);
if (strchr(pos, '-')==NULL)
{
wid->SetX2(atoi(pos));
}
else
{
wid->SetX2(0);
}
posTok.Next(pos);
if (strchr(pos, '-')==NULL)
{
wid->SetY2(atoi(pos));
}
else
{
wid->SetY2(0);
}
}
else if (strcmp(msg,"TYPE")==0)
{
msgTok.Next(msg);
mixMaxType = atoi(msg);
}
}
if (strcmp(messageType,"HSHELL_WINDOWCREATED")==0)
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HSHELL_WINDOWCREATED window title is:");
OutputDebugString(wid->GetTitle());
}
CStdString s = wid->GetId();
char *ptr;
int length = s.GetLength();
ptr = s.GetBufferSetLength(length);
hash_insert(ptr,wid,&m_ht);
CreateAndShowWindow(wid);
DoClipping(1);
}
else if(strcmp(messageType,"HSHELL_WINDOWDESTROYED")==0)
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HSHELL_WINDOWDISTROYED window title is:");
OutputDebugString(wid->GetTitle());
}
CStdString s = wid->GetId();
char *ptr;
int length = s.GetLength();
ptr = s.GetBufferSetLength(length);
CWindowData* oldWinData = (CWindowData*) hash_del(ptr,&m_ht);
DestroyTaskbarWindow(oldWinData);
delete oldWinData;
DoClipping(1);
}
else if(strcmp(messageType,"HCBT_MINMAX")==0)
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HCBT_MINMAX");
}
//TODO
}
else if(strcmp(messageType,"HCBT_MOVESIZE")==0)
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type HCBT_MOVESIZE window title is:");
OutputDebugString(wid->GetTitle());
}
CStdString s = wid->GetId();
char *ptr;
int length = s.GetLength();
ptr = s.GetBufferSetLength(length);
CWindowData* movedWinData = (CWindowData*) hash_lookup(ptr,&m_ht);
if(movedWinData!=NULL)
{
movedWinData->SetX1(wid->GetX1());
movedWinData->SetX2(wid->GetX2());
movedWinData->SetY1(wid->GetY1());
movedWinData->SetY2(wid->GetY2());
DoClipping(1);
}
delete wid;
}
else if(strcmp(messageType,"CALLWNDPROC_WM_MOVING")==0)
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Message was of type CALLWNDPROC_WM_MOVING window title is:");
OutputDebugString(wid->GetTitle());
}
CStdString s = wid->GetId();
char *ptr;
int length = s.GetLength();
ptr = s.GetBufferSetLength(length);
CWindowData* movedWinData = (CWindowData*) hash_lookup(ptr,&m_ht);
if(movedWinData!=NULL)
{
movedWinData->SetX1(wid->GetX1());
movedWinData->SetX2(wid->GetX2());
movedWinData->SetY1(wid->GetY1());
movedWinData->SetY2(wid->GetY2());
////might be too much of an overhead forcing the redraw here. Might be better to do 'DoClipping(0)' instead?
DoClipping(1);
}
delete wid;
}
}
break;
case CHANNEL_EVENT_WRITE_COMPLETE:
{
}
break;
case CHANNEL_EVENT_WRITE_CANCELLED:
{
}
break;
default:
{
}
break;
}
}
else
{
}
}
VOID VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength)
{
UINT ui;
UNREFERENCED_PARAMETER(pInitHandle);
UNREFERENCED_PARAMETER(dataLength);
switch(event)
{
case CHANNEL_EVENT_INITIALIZED:
{
}
break;
case CHANNEL_EVENT_CONNECTED:
{
//
// open channel
//
ui = gpEntryPoints->pVirtualChannelOpen(gphChannel,&gdwOpenChannel,CHANNELNAME,(PCHANNEL_OPEN_EVENT_FN)VirtualChannelOpenEvent);
if (ui == CHANNEL_RC_OK)
{
}
else
{
MessageBox(NULL,TEXT("Open of RDP virtual channel failed"),TEXT("TS Window Clipper"),MB_OK);
}
if (ui != CHANNEL_RC_OK)
{
return;
}
}
break;
case CHANNEL_EVENT_V1_CONNECTED:
{
MessageBox(NULL,TEXT("Connecting to a non Windows 2000 Terminal Server"),TEXT("TS Window Clipper"),MB_OK);
}
break;
case CHANNEL_EVENT_DISCONNECTED:
{
}
break;
case CHANNEL_EVENT_TERMINATED:
{
//
// free the entry points table
//
LocalFree((HLOCAL)gpEntryPoints);
}
break;
default:
{
}
break;
}
}
BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
{
CHANNEL_DEF cd;
UINT uRet;
size_t s = 10;
hash_construct_table(&m_ht, s);
//
// allocate memory
//
gpEntryPoints = (PCHANNEL_ENTRY_POINTS) LocalAlloc(LPTR, pEntryPoints->cbSize);
memcpy(gpEntryPoints, pEntryPoints, pEntryPoints->cbSize);
//
// initialize CHANNEL_DEF structure
//
ZeroMemory(&cd, sizeof(CHANNEL_DEF));
strcpy(cd.name, CHANNELNAME); // ANSI ONLY
//
// register channel
//
uRet = gpEntryPoints->pVirtualChannelInit((LPVOID *)&gphChannel,(PCHANNEL_DEF)&cd, 1,VIRTUAL_CHANNEL_VERSION_WIN2000,(PCHANNEL_INIT_EVENT_FN)VirtualChannelInitEventProc);
if (uRet == CHANNEL_RC_OK)
{
if (ALWAYS__CLIP)
{
DoClipping(1);
}
}
else
{
MessageBox(NULL,TEXT("RDP Virtual channel Init Failed"),TEXT("TS Window Clipper"),MB_OK);
}
if (uRet != CHANNEL_RC_OK)
{
return FALSE;
}
//
// make sure channel was initialized
//
if (cd.options != CHANNEL_OPTION_INITIALIZED)
{
return FALSE;
}
return TRUE;
}
// data structure to transfer informations
typedef struct _WindowFromProcessOrThreadID
{
union
{
DWORD procId;
DWORD threadId;
};
HWND hWnd;
}Wnd4PTID;
// Callback procedure
BOOL CALLBACK PrivateEnumWindowsProc(HWND hwnd,LPARAM lParam)
{
DWORD procId;
DWORD threadId;
Wnd4PTID* tmp = (Wnd4PTID*)lParam;
// get the process/thread id of current window
threadId = GetWindowThreadProcessId(hwnd, &procId);
// check if the process/thread id equal to the one passed by lParam?
if(threadId == tmp->threadId || procId == tmp->procId)
{
// check if the window is a main window
// because there lots of windows belong to the same process/thread
LONG dwStyle = GetWindowLong(hwnd, GWL_STYLE);
if(dwStyle & WS_SYSMENU)
{
tmp->hWnd = hwnd;
return FALSE; // break the enumeration
}
}
return TRUE; // continue the enumeration
}
// Enumarate all the MainWindow of the system
HWND FindProcessMainWindow(DWORD procId)
{
Wnd4PTID tempWnd4ID;
tempWnd4ID.procId = procId;
if(!EnumWindows((WNDENUMPROC)PrivateEnumWindowsProc, (LPARAM)&tempWnd4ID))
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Found main process window");
}
return tempWnd4ID.hWnd;
}
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Could not find main process window");
}
return NULL;
}
void DoClipping(int forceRedraw)
{
//if main window handle is null, try to get it
if (m_mainWindowHandle==NULL)
{
m_mainWindowHandle = FindProcessMainWindow(GetCurrentProcessId());
//hide the window from taskbar and put at the back of the z order
if ( HIDE_TSAC_WINDOW ==1 )
{
ShowWindow(m_mainWindowHandle, SW_HIDE);
SetWindowLongPtr(m_mainWindowHandle, GWL_EXSTYLE,GetWindowLong(m_mainWindowHandle, GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
ShowWindow(m_mainWindowHandle, SW_SHOW);
}
SetWindowPos(m_mainWindowHandle, HWND_NOTOPMOST, 0, 0, 0, 0,SWP_NOMOVE | SWP_NOSIZE);
}
//if we have the handle, lets use it for the clipping
if (m_mainWindowHandle!=NULL)
{
RECT wRect;
GetWindowRect(m_mainWindowHandle,&wRect);
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Restarting clipping...");
}
m_regionResult = NULL;
if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )
{
OutputDebugString("-----------------------------------------------------------------------------");
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> starting printing of window table");
}
//enumerate though hashtable
if (&m_ht!=NULL)
{
hash_enumerate( &m_ht, CreateRegionFromWindowData);
}
if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> finished printing of window table");
OutputDebugString("-----------------------------------------------------------------------------");
}
if (m_regionResult==NULL)
{
if (ALWAYS__CLIP)
{
m_regionResult=CreateRectRgn(0,0,0,0);
}
else
{
m_regionResult = CreateRectRgn(0,0,wRect.right,wRect.bottom);
}
}
SetWindowRgn(m_mainWindowHandle,(HRGN__*)m_regionResult, TRUE);
if (forceRedraw==1)
{
// invalidate the window and force it to redraw
RedrawWindow(m_mainWindowHandle,NULL,NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
}
}
else
{
if (OUTPUT_DEBUG_INFO == 1 )
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Coulf not find window to clip");
}
}
}
void CreateRegionFromWindowData(char * key,void * value)
{
CWindowData* wd;
wd = (CWindowData*)value;
int x1=0,x2=0,y1=0,y2=0;
char strB[5];
char strT[5];
char strL[5];
char strR[5];
if (m_regionResult==NULL)
{
m_regionResult=CreateRectRgn(0,0,0,0);
}
if (OUTPUT_DEBUG_INFO == 1 && OUTPUT_WINDOW_TABLE_DEBUG_INFO != 1)
{
OutputDebugString("TS WINDOW CLIPPER :: CLIENT DLL :: Info --> Adding this window to cliping region");
OutputDebugString(wd->GetTitle());
}
if (OUTPUT_WINDOW_TABLE_DEBUG_INFO == 1 )
{
ltoa(wd->GetY2(),strB,10);
ltoa(wd->GetY1(),strT,10);
ltoa(wd->GetX2(),strR,10);
ltoa(wd->GetX1(),strL,10);
OutputDebugString("This window is in the table:");
OutputDebugString(wd->GetTitle());
OutputDebugString(wd->GetId());
OutputDebugString(strL);
OutputDebugString(strT);
OutputDebugString(strR);
OutputDebugString(strB);
OutputDebugString("*******************");
}
HRGN newRegion = CreateRectRgn(wd->GetX1(),wd->GetY1(),wd->GetX2(),wd->GetY2());
CombineRgn(m_regionResult, newRegion, m_regionResult, RGN_OR);
}
/*
Dummy procedure to catch when window is being maximised.
Need to tell the window on the server to do the same.
*/
LRESULT CALLBACK DummyWindowCallbackProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
//TODO
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void CreateAndShowWindow(CWindowData* wd)
{
if (classAlreadyRegistered==0)
{
static const char *szWndName = "WTSWinClipperDummy";
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = DummyWindowCallbackProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = 0;
wc.hCursor = 0;
wc.hbrBackground = 0;
wc.lpszMenuName = 0;
wc.lpszClassName = szWndName;
if (RegisterClass(&wc))
{
classAlreadyRegistered=1;
}
}
if (classAlreadyRegistered=1)
{
HWND hWnd = CreateWindow(TEXT("WTSWinClipperDummy"), wd->GetTitle(), WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
ShowWindow( hWnd, 3 );
SetWindowPos(hWnd,0,0,0,0,0,SWP_NOREDRAW);
wd->TaskbarWindowHandle = hWnd;
SetFocus(m_mainWindowHandle);
}
}
void DestroyTaskbarWindow(CWindowData* wd)
{
if (wd->TaskbarWindowHandle != NULL)
{
DestroyWindow(wd->TaskbarWindowHandle);
}
}
--- NEW FILE: clipper.h ---
//*********************************************************************************
//
//Title: Terminal Services Window Clipper
//
//Author: Martin Wickett
//
//Date: 2004
//
//*********************************************************************************
#define VER_FILETYPE VFT_DLL
#define VER_FILESUBTYPE VFT2_UNKNOWN
#define VER_FILEDESCRIPTION_STR "Virtual Channel sample DLL"
#define VER_INTERNALNAME_STR "sysinf_c.dll"
#define VER_ORIGINALFILENAME_STR "sysinf_c.dll"
#define STRICT
#define _
#include <windows.h>
#include <ntverp.h>
#include "common.ver"
#include <windows.h>
#include <stdio.h>
#include <wtsapi32.h>
#include <tchar.h>
#include <lmcons.h>
#ifdef TSDLL
#include <pchannel.h>
#include <cchannel.h>
#include <windows.h>
#include <winuser.h>
#endif
#include "hash.h"
#include "tokenizer.h"
#include "WindowData.h"
//
// definitions
//
#define CHANNELNAME "CLIPPER"
//
// GLOBAL variables
//
LPHANDLE gphChannel;
DWORD gdwOpenChannel;
PCHANNEL_ENTRY_POINTS gpEntryPoints;
hash_table m_ht;
HRGN m_regionResult;
HWND m_mainWindowHandle = NULL;
int classAlreadyRegistered=0;
int const ALWAYS__CLIP = 0;//set this to 0 to turn off clipping when there are no windows
int const HIDE_TSAC_WINDOW = 1;
int const OUTPUT_DEBUG_INFO = 0;
int const OUTPUT_WINDOW_TABLE_DEBUG_INFO = 0;
//
// declarations
//
void WINAPI VirtualChannelOpenEvent(DWORD openHandle, UINT event, LPVOID pdata, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags);
VOID VCAPITYPE VirtualChannelInitEventProc(LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength);
BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints);
void DoClipping(int forceRedraw);
void CreateRegionFromWindowData(char *,void *);
void CreateAndShowWindow(CWindowData* wd);
void DestroyTaskbarWindow(CWindowData* wd);
--- NEW FILE: hash.cpp ---
#include <string.h>
#include <stdlib.h>
/* #define NDEBUG */
#include <assert.h>
#include "hash.h"
/*
** public domain code by Jerry Coffin.
**
** Tested with Visual C 1.0 and Borland C 3.1.
** Compiles without warnings, and seems like it should be pretty
** portable.
*/
/* HW: HenkJan Wolthuis, 1997, public domain
changed functionnames, all public functions now have a 'hash_' prefix
minor editing, marked 'm all(?) with a description
removed a bug in hash_del and one in hash_enumerate
added some assertions
added a 'count' member to hold the number of elements
added hash_sorted_enum, sometimes useful
changed the testmain
*/
/*
** RBS: Bob Stout, 2003, public domain
**
** 1. Fixed some problems in hash() static function.
** 2. Use unsigned shorts for hash values. This was implicit in the original
** which was written for PC's using early Microsoft and Borland compilers.
*/
/* HW: #define to allow duplicate keys, they're added before the existing
key so hash_lookup finds the last one inserted first (LIFO)
when not defined, hash_insert swaps the datapointers, returning a
pointer to the old data
*/
/* #define DUPLICATE_KEYS */
/*
** These are used in freeing a table. Perhaps I should code up
** something a little less grungy, but it works, so what the heck.
*/
static void (*function)(void *) = NULL;
static hash_table *the_table = NULL;
/* Initialize the hash_table to the size asked for. Allocates space
** for the correct number of pointers and sets them to NULL. If it
** can't allocate sufficient memory, signals error by setting the size
** of the table to 0.
*/
/*HW: changed, now returns NULL on malloc-failure */
hash_table *hash_construct_table( hash_table *table, size_t size )
{
size_t i;
bucket **temp;
table->size = size;
table->count = 0;
table->table = (bucket **)malloc(sizeof(bucket *) * size);
temp = table->table;
if( NULL == temp )
{
table->size = 0;
return NULL; /*HW: was 'table' */
}
for( i=0; i<size; i++ )
temp[i] = NULL;
return table;
}
/*
** Hashes a string to produce an unsigned short, which should be
** sufficient for most purposes.
** RBS: fixed per user feedback from Steve Greenland
*/
static unsigned short hash(char *string)
{
unsigned short ret_val = 0;
int i;
while (*string)
{
/*
** RBS: Added conditional to account for strings in which the
** length is less than an integral multiple of sizeof(int).
**
** Note: This fixes the problem of hasing trailing garbage, but
** doesn't fix the problem with some CPU's which can't align on
** byte boundries. Any decent C compiler *should* fix this, but
** it still might extract a performance hit. Also unaddressed is
** what happens when using a CPU which addresses data only on
** 4-byte boundries when it tries to work with a pointer to a
** 2-byte unsigned short.
*/
if (strlen(string) >= sizeof(unsigned short))
i = *(unsigned short *)string;
else i = (unsigned short)(*string);
ret_val ^= i;
ret_val <<= 1;
string ++;
}
return ret_val;
}
/*
** Insert 'key' into hash table.
** Returns pointer to old data associated with the key, if any, or
** NULL if the key wasn't in the table previously.
*/
/* HW: returns NULL if malloc failed */
void *hash_insert( char *key, void *data, hash_table *table )
{
unsigned short val = hash(key) % table->size;
bucket *ptr;
assert( NULL != key );
/*
** NULL means this bucket hasn't been used yet. We'll simply
** allocate space for our new bucket and put our data there, with
** the table pointing at it.
*/
if( NULL == (table->table)[val] )
{
(table->table)[val] = (bucket *)malloc(sizeof(bucket));
if( NULL == (table->table)[val] )
return NULL;
if( NULL == ((table->table)[val]->key = (char*) malloc(strlen(key)+1)) )
{
free( (table->table)[val] );
(table->table)[val] = NULL;
return NULL;
}
strcpy( (table->table)[val]->key, key);
(table->table)[val] -> next = NULL;
(table->table)[val] -> data = data;
table->count++; /* HW */
return (table->table)[val] -> data;
}
/* HW: added a #define so the hashtable can accept duplicate keys */
#ifndef DUPLICATE_KEYS
/*
** This spot in the table is already in use. See if the current string
** has already been inserted, and if so, increment its count.
*/ /* HW: ^^^^^^^^ ?? */
for( ptr = (table->table)[val]; NULL != ptr; ptr = ptr->next )
if( 0 == strcmp(key, ptr->key) )
{
void *old_data;
old_data = ptr->data;
ptr->data = data;
return old_data;
}
#endif
/*
** This key must not be in the table yet. We'll add it to the head of
** the list at this spot in the hash table. Speed would be
** slightly improved if the list was kept sorted instead. In this case,
** this code would be moved into the loop above, and the insertion would
** take place as soon as it was determined that the present key in the
** list was larger than this one.
*/
ptr = (bucket *)malloc(sizeof(bucket));
if( NULL == ptr )
return NULL; /*HW: was 0 */
if( NULL == (ptr -> key = (char*) malloc(strlen(key)+1)) )
{
free(ptr);
return NULL;
}
strcpy( ptr->key, key );
ptr -> data = data;
ptr -> next = (table->table)[val];
(table->table)[val] = ptr;
table->count++; /* HW */
return data;
}
/*
** Look up a key and return the associated data. Returns NULL if
** the key is not in the table.
*/
void *hash_lookup( char *key, hash_table *table )
{
unsigned short val = hash(key) % table->size;
bucket *ptr;
assert( NULL != key );
if(NULL == (table->table)[val])
return NULL;
for( ptr = (table->table)[val]; NULL != ptr; ptr = ptr->next )
{
if(0 == strcmp( key, ptr -> key ) )
return ptr->data;
}
return NULL;
}
/*
** Delete a key from the hash table and return associated
** data, or NULL if not present.
*/
void *hash_del(char *key, hash_table *table)
{
unsigned short val = hash(key) % table->size;
void *data;
bucket *ptr, *last = NULL;
assert( NULL != key );
if( NULL == (table->table)[val] )
return NULL; /* HW: was 'return 0' */
/*
** Traverse the list, keeping track of the previous node in the list.
** When we find the node to delete, we set the previous node's next
** pointer to point to the node after ourself instead. We then delete
** the key from the present node, and return a pointer to the data it
** contains.
*/
for( last = NULL, ptr = (table->table)[val];
NULL != ptr;
last = ptr, ptr = ptr->next )
{
if( 0 == strcmp( key, ptr -> key) )
{
if( last != NULL )
{
data = ptr -> data;
last -> next = ptr -> next;
free( ptr->key );
free( ptr );
table->count--; /* HW */
return data;
}
/* If 'last' still equals NULL, it means that we need to
** delete the first node in the list. This simply consists
** of putting our own 'next' pointer in the array holding
** the head of the list. We then dispose of the current
** node as above.
*/
else
{
/* HW: changed this bit to match the comments above */
data = ptr->data;
(table->table)[val] = ptr->next;
free( ptr->key );
free( ptr );
table->count--; /* HW */
return data;
}
}
}
/*
** If we get here, it means we didn't find the item in the table.
** Signal this by returning NULL.
*/
return NULL;
}
/*
** free_table iterates the table, calling this repeatedly to free
** each individual node. This, in turn, calls one or two other
** functions - one to free the storage used for the key, the other
** passes a pointer to the data back to a function defined by the user,
** process the data as needed.
*/
static void free_node( char *key, void *data )
{
(void) data;
assert( NULL != key );
if( NULL != function )
{
function( hash_del( key, the_table ) );
}
else
hash_del( key, the_table );
}
/*
** Frees a complete table by iterating over it and freeing each node.
** the second parameter is the address of a function it will call with a
** pointer to the data associated with each node. This function is
** responsible for freeing the data, or doing whatever is needed with
** it.
*/
void hash_free_table( hash_table *table, void (*func)(void *) )
{
function = func;
the_table = table;
hash_enumerate( table, free_node );
free( table->table );
table->table = NULL;
table->size = 0;
table->count = 0; /* HW */
the_table = NULL;
function = NULL;
}
/*
** Simply invokes the function given as the second parameter for each
** node in the table, passing it the key and the associated data.
*/
void hash_enumerate( hash_table *table, void (*func)(char *, void *) )
{
unsigned i;
bucket *temp;
bucket *swap;
for( i=0; i<table->size; i++ )
{
if( NULL != (table->table)[i] )
{
/* HW: changed this loop */
temp = (table->table)[i];
while( NULL != temp )
{
/* HW: swap trick, in case temp is freed by 'func' */
swap = temp->next;
func( temp -> key, temp->data );
temp = swap;
}
}
}
}
/* HW: added hash_sorted_enum()
hash_sorted_enum is like hash_enumerate but gives
sorted output. This is much slower than hash_enumerate, but
sometimes nice for printing to a file...
*/
typedef struct sort_struct
{
char *key;
void *data;
} sort_struct;
static sort_struct *sortmap = NULL;
static int counter = 0;
/* HW: used as 'func' for hash_enumerate */
static void key_get( char *key, void *data )
{
sortmap[ counter ].key = key;
sortmap[ counter ].data = data;
counter++;
}
/* HW: used for comparing the keys in qsort */
static int key_comp( const void* a, const void *b )
{
return strcmp( (*(sort_struct*)a).key, (*(sort_struct*)b).key );
}
/* HW: it's a compromise between speed and space. this one needs
table->count * sizeof( sort_struct) memory.
Another approach only takes count*sizeof(char*), but needs
to hash_lookup the data of every key after sorting the key.
returns 0 on malloc failure, 1 on success
*/
int hash_sorted_enum( hash_table *table, void (*func)( char *, void *) )
{
int i;
/* nothing to do ! */
if( NULL == table || 0 == table->count || NULL == func )
return 0;
/* malloc an pointerarray for all hashkey's and datapointers */
if( NULL == ( sortmap = (sort_struct*) malloc( sizeof( sort_struct ) * table->count)) )
return 0;
/* copy the pointers to the hashkey's */
counter = 0;
hash_enumerate( table, key_get );
/* sort the pointers to the keys */
qsort( sortmap, table->count, sizeof(sort_struct), key_comp );
/* call the function for each node */
for( i=0; i <abs( (table->count)); i++ )
{
func( sortmap[i].key, sortmap[i].data );
}
/* free the pointerarray */
free( sortmap );
sortmap = NULL;
return 1;
}
/* HW: changed testmain */
#define TEST
#ifdef TEST
#include <stdio.h>
//#include "snip_str.h" /* for strdup() */
FILE *o;
void fprinter(char *string, void *data)
{
fprintf(o,"%s: %s\n", string, (char *)data);
}
void printer(char *string, void *data)
{
printf("%s: %s\n", string, (char *)data);
}
/* function to pass to hash_free_table */
void strfree( void *d )
{
/* any additional processing goes here (if you use structures as data) */
/* free the datapointer */
free(d);
}
int main(void)
{
hash_table table;
char *strings[] = {
"The first string",
"The second string",
"The third string",
"The fourth string",
"A much longer string than the rest in this example.",
"The last string",
NULL
};
char *junk[] = {
"The first data",
"The second data",
"The third data",
"The fourth data",
"The fifth datum",
"The sixth piece of data"
};
int i;
void *j;
hash_construct_table(&table,211);
/* I know, no checking on strdup ;-)), but using strdup
to demonstrate hash_table_free with a functionpointer */
for (i = 0; NULL != strings[i]; i++ )
hash_insert( strings[i], strdup(junk[i]), &table );
/* enumerating to a file */
if( NULL != (o = fopen("HASH.HSH","wb")) )
{
fprintf( o, "%d strings in the table:\n\n", table.count );
hash_enumerate( &table, fprinter );
fprintf( o, "\nsorted by key:\n");
hash_sorted_enum( &table, fprinter );
fclose( o );
}
/* enumerating to screen */
hash_sorted_enum( &table, printer );
printf("\n");
/* delete 3 strings, should be 3 left */
for( i=0; i<3; i++ )
{
/* hash_del returns a pointer to the data */
strfree( hash_del( strings[i], &table) );
}
hash_enumerate( &table, printer);
for (i=0;NULL != strings[i];i++)
{
j = hash_lookup(strings[i], &table);
if (NULL == j)
printf("\n'%s' is not in the table", strings[i]);
else
printf("\n%s is still in the table.", strings[i]);
}
hash_free_table( &table, strfree );
return 0;
}
#endif /* TEST */
--- NEW FILE: hash.h ---
/* HW: HenkJan Wolthuis, 1997 */
#ifndef HASH__H
#define HASH__H
#include <stddef.h> /* For size_t */
/*
** A hash table consists of an array of these buckets. Each bucket
** holds a copy of the key, a pointer to the data associated with the
** key, and a pointer to the next bucket that collided with this one,
** if there was one.
*/
typedef struct bucket {
char *key;
void *data;
struct bucket *next;
} bucket;
/*
** This is what you actually declare an instance of to create a table.
** You then call 'construct_table' with the address of this structure,
** and a guess at the size of the table. Note that more nodes than this
** can be inserted in the table, but performance degrades as this
** happens. Performance should still be quite adequate until 2 or 3
** times as many nodes have been inserted as the table was created with.
*/
typedef struct hash_table {
size_t size;
size_t count; /* HW */
bucket **table;
} hash_table;
/*
** This is used to construct the table. If it doesn't succeed, it sets
** the table's size to 0, and the pointer to the table to NULL.
*/
/* HW: returns NULL if it fails */
hash_table *hash_construct_table(hash_table *table,size_t size);
/*
** Inserts a pointer to 'data' in the table, with a copy of 'key' as its
** key. Note that this makes a copy of the key, but NOT of the
** associated data.
*/
void *hash_insert(char *key,void *data,struct hash_table *table);
/*
** Returns a pointer to the data associated with a key. If the key has
** not been inserted in the table, returns NULL.
*/
void *hash_lookup(char *key,struct hash_table *table);
/*
** Deletes an entry from the table. Returns a pointer to the data that
** was associated with the key so the calling code can dispose of it
** properly.
*/
void *hash_del(char *key,struct hash_table *table);
/*
** Goes through a hash table and calls the function passed to it
** for each node that has been inserted. The function is passed
** a pointer to the key, and a pointer to the data associated
** with it.
*/
void hash_enumerate( hash_table *table,void (*func)(char *,void *));
/* HW: same as above, but sorted output ( sorted on 'key') */
int hash_sorted_enum( hash_table *table, void(*func)(char *, void*));
/*
** Frees a hash table. For each node that was inserted in the table,
** it calls the function whose address it was passed, with a pointer
** to the data that was in the table. The function is expected to
** free the data. Typical usage would be:
** free_table(&table, free);
** if the data placed in the table was dynamically allocated, or:
** free_table(&table, NULL);
** if not. ( If the parameter passed is NULL, it knows not to call
** any function with the data. )
*/
void hash_free_table(hash_table *table, void (*func)(void *));
#endif /* HASH__H */
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click