995 lines
22 KiB
C
995 lines
22 KiB
C
//
|
|
// HET.C
|
|
// Hosted Entity Tracker
|
|
//
|
|
// Copyright(c) Microsoft 1997-
|
|
//
|
|
|
|
#include <as16.h>
|
|
|
|
|
|
//
|
|
// OSI and HET apis are the equivalent of the NT HOOK functionality.
|
|
// HET_DD apis are the equivalent of the NT display driver apis.
|
|
//
|
|
|
|
/////
|
|
//
|
|
// HOOK functionality
|
|
//
|
|
/////
|
|
|
|
|
|
|
|
BOOL WINAPI OSIIsWindowScreenSaver16(HWND hwnd)
|
|
{
|
|
BOOL fScreenSaver;
|
|
|
|
DebugEntry(OSIIsWindowScreenSaver16);
|
|
|
|
//
|
|
// If there is no screen saver active, this window can't be one.
|
|
//
|
|
fScreenSaver = FALSE;
|
|
SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &fScreenSaver, 0);
|
|
if (fScreenSaver)
|
|
{
|
|
char szClassName[64];
|
|
|
|
//
|
|
// Is the class name WindowsScreenSaverClass? This is what all
|
|
// screen savers using the Win95 toolkit use. BOGUS BUGBUG
|
|
// EXCEPT FOR THE IE4 CHANNEL SCREEN SAVER.
|
|
//
|
|
if (!GetClassName(hwnd, szClassName, sizeof(szClassName)) ||
|
|
lstrcmp(szClassName, HET_SCREEN_SAVER_CLASS))
|
|
{
|
|
fScreenSaver = FALSE;
|
|
}
|
|
}
|
|
|
|
DebugExitBOOL(OSIIsWindowScreenSaver16, fScreenSaver);
|
|
return(fScreenSaver);
|
|
}
|
|
|
|
|
|
//
|
|
// OSIStartWindowTracking16()
|
|
//
|
|
// This installs our global call window proc hook then watches windows
|
|
// being created, destroyed, shown, hidden and looks for relationships via
|
|
// process or related process info to the currently shared windows.
|
|
//
|
|
BOOL WINAPI OSIStartWindowTracking16(void)
|
|
{
|
|
BOOL rc = FALSE;
|
|
|
|
DebugEntry(OSIStartWindowTracking16);
|
|
|
|
ASSERT(!g_hetTrackHook);
|
|
|
|
//
|
|
// Install window/task tracking hook
|
|
//
|
|
g_hetTrackHook = SetWindowsHookEx(WH_CALLWNDPROC, HETTrackProc, g_hInstAs16, NULL);
|
|
if (!g_hetTrackHook)
|
|
{
|
|
ERROR_OUT(("Can't install WH_CALLWNDPROC hook"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Install event hook
|
|
//
|
|
g_hetEventHook = SetWindowsHookEx(WH_CBT, HETEventProc, g_hInstAs16, NULL);
|
|
if (!g_hetEventHook)
|
|
{
|
|
ERROR_OUT(("Can't install WH_CBT hook"));
|
|
DC_QUIT;
|
|
}
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(OSIStartWindowTracking16, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
//
|
|
// OSIStopWindowTracking16()
|
|
//
|
|
void WINAPI OSIStopWindowTracking16(void)
|
|
{
|
|
DebugEntry(OSIStopWindowTracking16);
|
|
|
|
//
|
|
// Remove Graphic Output hooks
|
|
//
|
|
HETDDViewing(FALSE);
|
|
|
|
//
|
|
// Remove event hook
|
|
//
|
|
if (g_hetEventHook)
|
|
{
|
|
UnhookWindowsHookEx(g_hetEventHook);
|
|
g_hetEventHook = NULL;
|
|
}
|
|
|
|
//
|
|
// Remove window/task tracking hook
|
|
//
|
|
if (g_hetTrackHook)
|
|
{
|
|
UnhookWindowsHookEx(g_hetTrackHook);
|
|
g_hetTrackHook = NULL;
|
|
}
|
|
|
|
DebugExitVOID(OSIStopWindowTracking16);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETEventProc()
|
|
// This is a global CBT hook that prevents the screensaver from kicking
|
|
// in when sharing.
|
|
//
|
|
LRESULT CALLBACK HETEventProc
|
|
(
|
|
int nCode,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LRESULT lResult;
|
|
|
|
DebugEntry(HETEventProc);
|
|
|
|
if ((nCode == HCBT_SYSCOMMAND) && (wParam == SC_SCREENSAVE))
|
|
{
|
|
// Prevent the screen saver from starting. NONZERO means disallow.
|
|
WARNING_OUT(("Preventing screensaver from starting, we're currently sharing"));
|
|
lResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
lResult = CallNextHookEx(g_hetEventHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
DebugExitDWORD(HETEventProc, lResult);
|
|
return(lResult);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETTrackProc()
|
|
//
|
|
// This is the global hook that watches for windows coming & going,
|
|
// showing & hiding to see if new ones related to shared ones should also
|
|
// be shared. This covers related processes as well as related windows.
|
|
//
|
|
LRESULT CALLBACK HETTrackProc
|
|
(
|
|
int nCode,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LPCWPSTRUCT lpCwp;
|
|
LPWINDOWPOS lpPos;
|
|
LRESULT lResult;
|
|
|
|
DebugEntry(HETTrackProc);
|
|
|
|
//
|
|
// wParam is a BOOL, TRUE if this is interthread
|
|
// lParam is a pointer to a CWPSTRUCT
|
|
//
|
|
lpCwp = (LPCWPSTRUCT)lParam;
|
|
ASSERT(!IsBadReadPtr(lpCwp, sizeof(*lpCwp)));
|
|
|
|
//
|
|
// We better be tracking still
|
|
//
|
|
ASSERT(g_hetTrackHook);
|
|
|
|
//
|
|
// Skip calls that happen in CONF itself. This is our implementation
|
|
// of the SKIP_OWNPROCESS WinEvent option in NT's hook dll
|
|
//
|
|
if (GetCurrentTask() != g_hCoreTask)
|
|
{
|
|
switch (lpCwp->message)
|
|
{
|
|
case WM_NCCREATE:
|
|
HETHandleCreate(lpCwp->hwnd);
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
HETHandleDestroy(lpCwp->hwnd);
|
|
break;
|
|
|
|
case WM_NCPAINT:
|
|
//
|
|
// This will catch being shown before WINDOWPOSCHANGED does.
|
|
// We still keep that for a catch all.
|
|
//
|
|
if (IsWindowVisible(lpCwp->hwnd))
|
|
{
|
|
HETHandleShow(lpCwp->hwnd, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_WINDOWPOSCHANGED:
|
|
lpPos = (LPWINDOWPOS)lpCwp->lParam;
|
|
ASSERT(!IsBadReadPtr(lpPos, sizeof(WINDOWPOS)));
|
|
|
|
if (!(lpPos->flags & SWP_NOMOVE))
|
|
HETCheckParentChange(lpCwp->hwnd);
|
|
|
|
if (lpPos->flags & SWP_SHOWWINDOW)
|
|
HETHandleShow(lpCwp->hwnd, TRUE);
|
|
else if (lpPos->flags & SWP_HIDEWINDOW)
|
|
HETHandleHide(lpCwp->hwnd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
lResult = CallNextHookEx(g_hetTrackHook, nCode, wParam, lParam);
|
|
|
|
DebugExitDWORD(HETTrackProc, lResult);
|
|
return(lResult);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETHandleCreate()
|
|
//
|
|
void HETHandleCreate(HWND hwnd)
|
|
{
|
|
HET_TRACK_INFO hti;
|
|
UINT hostType;
|
|
|
|
DebugEntry(HETHandleCreate);
|
|
|
|
//
|
|
// Ignore child windows
|
|
//
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
if (GetParent(hwnd) != g_osiDesktopWindow)
|
|
{
|
|
TRACE_OUT(("Skipping child window %04x create", hwnd));
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
hti.idThread = g_lpfnGetWindowThreadProcessId(hwnd, &hti.idProcess);
|
|
|
|
//
|
|
// Ignore special shell threads
|
|
//
|
|
if (HET_IsShellThread(hti.idThread))
|
|
{
|
|
TRACE_OUT(("Skipping shell thread window %04x create", hwnd));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// We don't need to ignore menus. Only when first shared do we skip
|
|
// menus. The cached one we never want to share. The others will
|
|
// go away almost immediately. From now on, we treat them the same
|
|
// as other windows.
|
|
//
|
|
|
|
//
|
|
// Figure out what to do.
|
|
//
|
|
hti.hwndUs = hwnd;
|
|
hti.cWndsApp = 0;
|
|
hti.cWndsSharedThread = 0;
|
|
hti.cWndsSharedProcess = 0;
|
|
|
|
UpOneLevel:
|
|
EnumWindows(HETShareEnum, (LPARAM)(LPHET_TRACK_INFO)&hti);
|
|
|
|
if (hti.cWndsSharedThread)
|
|
{
|
|
TRACE_OUT(("New window %04x in shared thread %08lx",
|
|
hwnd, hti.idThread));
|
|
hostType = HET_HOSTED_PERMANENT | HET_HOSTED_BYTHREAD;
|
|
}
|
|
else if (hti.cWndsSharedProcess)
|
|
{
|
|
TRACE_OUT(("New window %04x in shared process %08lx",
|
|
hwnd, hti.idProcess));
|
|
hostType = HET_HOSTED_PERMANENT | HET_HOSTED_BYPROCESS;
|
|
}
|
|
else if (hti.cWndsApp)
|
|
{
|
|
//
|
|
// There's another window in our app, but none are shared. So don't
|
|
// share us either.
|
|
//
|
|
TRACE_OUT(("New window %04x in unshared process %08lx",
|
|
hwnd, hti.idProcess));
|
|
DC_QUIT;
|
|
}
|
|
else
|
|
{
|
|
DWORD idParentProcess;
|
|
|
|
// Loop through our ancestor processes (no thread info at this point)
|
|
HETGetParentProcessID(hti.idProcess, &idParentProcess);
|
|
|
|
if (!idParentProcess)
|
|
{
|
|
TRACE_OUT(("Can't get parent of process %08lx", hti.idProcess));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// We know if we got here that all our favorite fields are still
|
|
// zero. So just loop! But NULL out idThread to avoid matching
|
|
// anything while we look at our parent.
|
|
//
|
|
TRACE_OUT(("First window %04x in process %08lx, checking parent %08lx",
|
|
hwnd, hti.idProcess, idParentProcess));
|
|
|
|
hti.idThread = 0;
|
|
hti.idProcess = idParentProcess;
|
|
goto UpOneLevel;
|
|
}
|
|
|
|
//
|
|
// OK, we are going to share this. No need to repaint, all our
|
|
// notifications are synchronous.
|
|
//
|
|
OSIShareWindow16(hwnd, hostType, FALSE, TRUE);
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(HETHandleCreate);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETHandleDestroy()
|
|
// Handles the destruction of a window
|
|
//
|
|
void HETHandleDestroy(HWND hwnd)
|
|
{
|
|
DebugEntry(HETHandleDestroy);
|
|
|
|
//
|
|
// Blow away our cache. Our cache holds the last window
|
|
// drawing happened for, whether it was shared or not,
|
|
// to let us more quickly decide whether we care.
|
|
//
|
|
OSIUnshareWindow16(hwnd, TRUE);
|
|
|
|
if (hwnd == g_oeLastWindow)
|
|
{
|
|
TRACE_OUT(("Tossing oe cached window %04x", g_oeLastWindow));
|
|
g_oeLastWindow = NULL;
|
|
}
|
|
|
|
DebugExitVOID(HETHandleDestroy);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETHandleShow()
|
|
//
|
|
void HETHandleShow
|
|
(
|
|
HWND hwnd,
|
|
BOOL fForceRepaint
|
|
)
|
|
{
|
|
UINT hostType;
|
|
HET_TRACK_INFO hti;
|
|
|
|
DebugEntry(HETHandleShow);
|
|
|
|
hostType = HET_GetHosting(hwnd);
|
|
|
|
//
|
|
// If this window is a real child, clear the hosting property. Usually
|
|
// one isn't there. But in the case of a top level window becoming
|
|
// a child of another, we want to wipe out junk.
|
|
//
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
if (GetParent(hwnd) != g_osiDesktopWindow)
|
|
{
|
|
TRACE_OUT(("Skipping child window 0x%04x show", hwnd));
|
|
if (hostType)
|
|
{
|
|
WARNING_OUT(("Unsharing shared child window 0x%04 from SHOW", hwnd));
|
|
OSIUnshareWindow16(hwnd, TRUE);
|
|
}
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Is this guy already shared? Nothing to do if so. Unlike NT,
|
|
// we don't get async notifications.
|
|
//
|
|
if (hostType)
|
|
{
|
|
TRACE_OUT(("Window %04x already shared, ignoring show", hwnd));
|
|
DC_QUIT;
|
|
}
|
|
|
|
|
|
//
|
|
// Here's where we also enumerate the top level windows and find a
|
|
// match. But we DO not track across processes in this case. Instead
|
|
// we look at the owner if there is one.
|
|
//
|
|
// This solves the create-as-a-child then change to a top level
|
|
// window problem, like combo dropdowns.
|
|
//
|
|
|
|
hti.idThread = g_lpfnGetWindowThreadProcessId(hwnd, &hti.idProcess);
|
|
|
|
//
|
|
// Ignore special shell threads
|
|
//
|
|
if (HET_IsShellThread(hti.idThread))
|
|
{
|
|
TRACE_OUT(("Skipping shell thread window 0x%04x show", hwnd));
|
|
DC_QUIT;
|
|
}
|
|
|
|
hti.hwndUs = hwnd;
|
|
hti.cWndsApp = 0;
|
|
hti.cWndsSharedThread = 0;
|
|
hti.cWndsSharedProcess = 0;
|
|
|
|
EnumWindows(HETShareEnum, (LPARAM)(LPHET_TRACK_INFO)&hti);
|
|
|
|
//
|
|
// These kinds of windows are always only temp shared. They don't
|
|
// start out as top level windows that we saw from the beginning or
|
|
// watched created. These are SetParent() or menu kinds of dudes, so
|
|
// for a lot of reasons we're plain safer sharing these babies only
|
|
// temporarily
|
|
//
|
|
|
|
//
|
|
// Anything else shared on this thread/process, the decision is easy.
|
|
// Otherwise, we look at the ownership trail.
|
|
//
|
|
if (!hti.cWndsSharedThread && !hti.cWndsSharedProcess)
|
|
{
|
|
HWND hwndOwner;
|
|
|
|
//
|
|
// Does it have an owner that is shared?
|
|
//
|
|
hwndOwner = hwnd;
|
|
while (hwndOwner = GetWindow(hwndOwner, GW_OWNER))
|
|
{
|
|
if (HET_GetHosting(hwndOwner))
|
|
{
|
|
TRACE_OUT(("Found shared owner %04x of window %04x", hwndOwner, hwnd));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hwndOwner)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We maybe getting this too late, like in the case of a menu coming up,
|
|
// and it may have already painted/erased. So invalidate this baby.
|
|
// That's what the fForceRepaint parameter is for. That is only true
|
|
// when coming from WM_WINDOWPOSCHANGED after an explicit WM_SHOWWINDOW
|
|
// call. Most of the time, we catch WM_NCPAINT though, for show.
|
|
//
|
|
TRACE_OUT(("Sharing temporary window %04x", hwnd));
|
|
|
|
OSIShareWindow16(hwnd, HET_HOSTED_BYWINDOW | HET_HOSTED_TEMPORARY,
|
|
fForceRepaint, TRUE);
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(HETHandleShow);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETHandleHide()
|
|
//
|
|
void HETHandleHide(HWND hwnd)
|
|
{
|
|
UINT hostType;
|
|
|
|
DebugEntry(HETHandleHide);
|
|
|
|
hostType = HET_GetHosting(hwnd);
|
|
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
if (GetParent(hwnd) != GetDesktopWindow())
|
|
{
|
|
TRACE_OUT(("Skipping child window %04x hide", hwnd));
|
|
if (hostType)
|
|
{
|
|
WARNING_OUT(("Unsharing shared child window 0x%04 from HIDE", hwnd));
|
|
OSIUnshareWindow16(hwnd, TRUE);
|
|
}
|
|
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
if (!hostType)
|
|
{
|
|
//
|
|
// Unlike NT, we don't get hide notifications out of context, so
|
|
// we don't need to recount the top level guys.
|
|
//
|
|
TRACE_OUT(("Window %04x not shared, ignoring hide", hwnd));
|
|
}
|
|
else if (hostType & HET_HOSTED_TEMPORARY)
|
|
{
|
|
TRACE_OUT(("Unsharing temporary window %04x", hwnd));
|
|
OSIUnshareWindow16(hwnd, TRUE);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(hostType & HET_HOSTED_PERMANENT);
|
|
|
|
// Nothing to do
|
|
TRACE_OUT(("Window %04x permanently shared, ignoring hide", hwnd));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitVOID(HETHandleHide);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETCheckParentChange()
|
|
//
|
|
// On a windowposchange with MOVE, we make sure that no child window has the
|
|
// hosting property. When a window's parent changes, it is always moved,
|
|
// so that's the best way I have to check for it. Since we only look at
|
|
// top level windows, converted-to-children windows will stay shared forever
|
|
// and won't show up in the share menu.
|
|
//
|
|
// This is NOT perfect. If the child is not moving to a different position
|
|
// relative to the two parents, we won't see anything. But for the case
|
|
// where one is switching to/from top level, its very likely we will come
|
|
// through here. More likely than checking for hide/show.
|
|
//
|
|
void HETCheckParentChange(HWND hwnd)
|
|
{
|
|
DebugEntry(HETCheckParentChange);
|
|
|
|
if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
if (GetParent(hwnd) != GetDesktopWindow())
|
|
{
|
|
UINT hostType;
|
|
|
|
hostType = HET_GetHosting(hwnd);
|
|
if (hostType)
|
|
{
|
|
WARNING_OUT(("Unsharing shared child window 0x%04x from MOVE", hwnd));
|
|
OSIUnshareWindow16(hwnd, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
DebugExitVOID(HETCheckParentChange);
|
|
}
|
|
|
|
|
|
//
|
|
// HETShareEnum()
|
|
//
|
|
// This is the EnumWindows() callback. We stop when we find the first
|
|
// matching shared window (thread or process). We keep a running tally
|
|
// of the count of all top level windows in our process (not shared by
|
|
// thread or process) at the same time. This lets us do tracking.
|
|
//
|
|
BOOL CALLBACK HETShareEnum(HWND hwnd, LPARAM lParam)
|
|
{
|
|
LPHET_TRACK_INFO lphti = (LPHET_TRACK_INFO)lParam;
|
|
DWORD idProcess;
|
|
DWORD idThread;
|
|
UINT hostType;
|
|
BOOL rc = TRUE;
|
|
|
|
DebugEntry(HETShareEnum);
|
|
|
|
// Skip ourself.
|
|
if (hwnd == lphti->hwndUs)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Skip if window is gone.
|
|
idThread = g_lpfnGetWindowThreadProcessId(hwnd, &idProcess);
|
|
if (!idThread)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Do the processes match? If not, easy amscray
|
|
//
|
|
if (idProcess != lphti->idProcess)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
lphti->cWndsApp++;
|
|
|
|
hostType = HET_GetHosting(hwnd);
|
|
if (!hostType)
|
|
{
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Now, if this window is shared by thread or process, do the right
|
|
// thing.
|
|
//
|
|
if (hostType & HET_HOSTED_BYPROCESS)
|
|
{
|
|
// We have a match. We can return immediately.
|
|
lphti->cWndsSharedProcess++;
|
|
rc = FALSE;
|
|
}
|
|
else if (hostType & HET_HOSTED_BYTHREAD)
|
|
{
|
|
//
|
|
// For WOW apps, we don't want this one, if in a separate thread, to
|
|
// count. No matter what.
|
|
//
|
|
if (idThread == lphti->idThread)
|
|
{
|
|
lphti->cWndsSharedThread++;
|
|
rc = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(HETShareEnum, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// HET_IsShellThread()
|
|
// Returns TRUE if thread is one of shell's special threads
|
|
//
|
|
BOOL HET_IsShellThread(DWORD threadID)
|
|
{
|
|
BOOL rc;
|
|
|
|
DebugEntry(HET_IsShellThread);
|
|
|
|
if ((threadID == g_lpfnGetWindowThreadProcessId(HET_GetShellDesktop(), NULL)) ||
|
|
(threadID == g_lpfnGetWindowThreadProcessId(HET_GetShellTray(), NULL)))
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = FALSE;
|
|
}
|
|
|
|
DebugExitBOOL(HET_IsShellThread, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// OSIShareWindow16()
|
|
// This shares a window. This is called when
|
|
// * An app is unshared
|
|
// * A window is destroyed
|
|
// * A temporarily shared window is hidden
|
|
//
|
|
// This returns TRUE if it shared a window
|
|
//
|
|
BOOL WINAPI OSIShareWindow16
|
|
(
|
|
HWND hwnd,
|
|
UINT hostType,
|
|
BOOL fRepaint,
|
|
BOOL fUpdateCount
|
|
)
|
|
{
|
|
BOOL rc = FALSE;
|
|
|
|
DebugEntry(OSIShareWindow16);
|
|
|
|
//
|
|
// Set the property
|
|
//
|
|
if (!HET_SetHosting(hwnd, hostType))
|
|
{
|
|
ERROR_OUT(("Couldn't set shared property on window %04x", hwnd));
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Toss out our cache--it could have been a child of this one.
|
|
//
|
|
g_oeLastWindow = NULL;
|
|
|
|
TRACE_OUT(("Shared window %04x of type %04x", hwnd, hostType));
|
|
|
|
//
|
|
// Repaint it
|
|
//
|
|
if (fRepaint)
|
|
{
|
|
USR_RepaintWindow(hwnd);
|
|
}
|
|
|
|
if (fUpdateCount)
|
|
{
|
|
PostMessageNoFail(g_asMainWindow, DCS_NEWTOPLEVEL_MSG, TRUE, 0);
|
|
}
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(OSIShareWindow16, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// OSIUnshareWindow16()
|
|
// This unshares a window. This is called when
|
|
// * An app is unshared
|
|
// * A window is destroyed
|
|
// * A temporarily shared window is hidden
|
|
//
|
|
// This returns TRUE if it unshared a shared window.
|
|
//
|
|
BOOL WINAPI OSIUnshareWindow16
|
|
(
|
|
HWND hwnd,
|
|
BOOL fUpdateCount
|
|
)
|
|
{
|
|
BOOL rc = FALSE;
|
|
UINT hostType;
|
|
|
|
DebugEntry(OSIUnshareWindow16);
|
|
|
|
//
|
|
// This gets the old property and clears it in one step.
|
|
//
|
|
hostType = HET_ClearHosting(hwnd);
|
|
if (!hostType)
|
|
{
|
|
//
|
|
// Unlike NT, all the destroy notifications we get are synchronous.
|
|
// So we don't need to recalculate the total.
|
|
//
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRACE_OUT(("Unsharing window %04x of type %04x", hwnd, hostType));
|
|
|
|
//
|
|
// Toss our cache--the sharing status of some window has changed.
|
|
//
|
|
g_oeLastWindow = NULL;
|
|
|
|
//
|
|
// Update the top level count
|
|
//
|
|
if (fUpdateCount)
|
|
{
|
|
PostMessageNoFail(g_asMainWindow, DCS_NEWTOPLEVEL_MSG, FALSE, 0);
|
|
}
|
|
|
|
rc = TRUE;
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(OSI_UnshareWindow, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HET_WindowIsHosted()
|
|
// Returns TRUE if a window is shared. This is used by the IM code in its
|
|
// high level hooks.
|
|
//
|
|
BOOL HET_WindowIsHosted(HWND hwnd)
|
|
{
|
|
BOOL rc = FALSE;
|
|
HWND hwndParent;
|
|
|
|
DebugEntry(HETHookWindowIsHosted);
|
|
|
|
if (!hwnd)
|
|
DC_QUIT;
|
|
|
|
//
|
|
// Walk up to the top level window this one is inside of
|
|
//
|
|
while (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
|
|
{
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent == GetDesktopWindow())
|
|
break;
|
|
|
|
hwnd = hwndParent;
|
|
}
|
|
|
|
rc = HET_GetHosting(hwnd);
|
|
|
|
DC_EXIT_POINT:
|
|
DebugExitBOOL(HET_WindowIsHosted, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HETGetParentProcessID()
|
|
// Get parent process if this one
|
|
//
|
|
void HETGetParentProcessID
|
|
(
|
|
DWORD processID,
|
|
LPDWORD pParentProcessID
|
|
)
|
|
{
|
|
//
|
|
// Get the ID of the parent process
|
|
//
|
|
ASSERT(processID);
|
|
*pParentProcessID = GetProcessDword(processID, GPD_PARENT);
|
|
}
|
|
|
|
|
|
|
|
|
|
/////
|
|
//
|
|
// DISPLAY DRIVER functionality
|
|
//
|
|
/////
|
|
|
|
//
|
|
// HET_DDInit()
|
|
//
|
|
BOOL HET_DDInit(void)
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
//
|
|
// HET_DDTerm()
|
|
//
|
|
void HET_DDTerm(void)
|
|
{
|
|
DebugEntry(HET_DDTerm);
|
|
|
|
//
|
|
// Make sure we stop hosting
|
|
//
|
|
g_hetDDDesktopIsShared = FALSE;
|
|
OSIStopWindowTracking16();
|
|
|
|
DebugExitVOID(HET_DDTerm);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// HET_DDProcessRequest()
|
|
// Handles HET escapes
|
|
//
|
|
|
|
BOOL HET_DDProcessRequest
|
|
(
|
|
UINT fnEscape,
|
|
LPOSI_ESCAPE_HEADER pResult,
|
|
DWORD cbResult
|
|
)
|
|
{
|
|
BOOL rc = TRUE;
|
|
|
|
DebugEntry(HET_DDProcessRequest);
|
|
|
|
switch (fnEscape)
|
|
{
|
|
//
|
|
// NOTE:
|
|
// Unlike NT, we have no need of keeping a duplicated list of
|
|
// shared windows. We can make window calls directly, and can use
|
|
// GetProp to find out.
|
|
//
|
|
case HET_ESC_UNSHARE_ALL:
|
|
{
|
|
// Nothing to do
|
|
}
|
|
break;
|
|
|
|
case HET_ESC_SHARE_DESKTOP:
|
|
{
|
|
ASSERT(!g_hetDDDesktopIsShared);
|
|
g_hetDDDesktopIsShared = TRUE;
|
|
}
|
|
break;
|
|
|
|
case HET_ESC_UNSHARE_DESKTOP:
|
|
{
|
|
ASSERT(g_hetDDDesktopIsShared);
|
|
g_hetDDDesktopIsShared = FALSE;
|
|
HETDDViewing(FALSE);
|
|
}
|
|
break;
|
|
|
|
case HET_ESC_VIEWER:
|
|
{
|
|
HETDDViewing(((LPHET_VIEWER)pResult)->viewersPresent != 0);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ERROR_OUT(("Unrecognized HET escape"));
|
|
rc = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
DebugExitBOOL(HET_DDProcessRequest, rc);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// HETDDViewing()
|
|
//
|
|
// Called when viewing of our shared apps starts/stops. Naturally, no longer
|
|
// sharing anything stops viewing also.
|
|
//
|
|
void HETDDViewing(BOOL fViewers)
|
|
{
|
|
DebugEntry(HETDDViewing);
|
|
|
|
if (g_oeViewers != fViewers)
|
|
{
|
|
g_oeViewers = fViewers;
|
|
OE_DDViewing(fViewers);
|
|
}
|
|
|
|
DebugExitVOID(HETDDViewing);
|
|
}
|