#include <windows.h>
// Quelltext für Visual C++ 6.0, ausnahmsweise .CPP für Referenzparameter
// Funktion: "Magnetische Fenster" à la WinAmp oder KDE
// h#s 08/02
// In Einstellung "DEBUG" ist der Compiler-Schalter "/GZ" zu entfernen!
#pragma comment(linker,"/ALIGN:4096 /DLL /MERGE:.rsrc=.rdata /SECTION:.shared,RWS /RELEASE /NODEFAULTLIB")
#pragma data_seg(".shared")
HHOOK Hook=0; // Initialisierung ist notwendig,
int SnapW=6; // sonst ist's "bss_seg" und kein "data_seg"
//#pragma data_seg()
HHOOK HookProcess; // Initialisierung für NT-Ladbarkeit? -> bss_seg
#define MAXINT 0x7FFFFFFF;
typedef enum {sleft=1, stop=2, sright=4, sbottom=8}; //Schnapp-Maske
int _fastcall Abs(int x) {
if (x<0) x=-x;
return x;
}
void _fastcall AbsMin(long &x2, long x) {
//Setzt x2 auf das Betragsminimum beider vzb. Zahlen
if (Abs(x2)>Abs(x)) x2=x;
}
void _stdcall AdjustRect(HWND W, RECT &R, BYTE snap) {
//Modifiziert Zielrechteck <R> des Fensters <W> in Abhängigkeit
//der Nachbar- und des Elternfensters an den durch <snap> erlaubten Kanten
RECT RP,R2; //Eltern- und Geschwister-Rechteck
POINT MP; //Verschiebung
HWND W2; //Eltern- oder Geschwister-Fenster
char s[8]; //für Klassenname (IconTitle sollte ausgeschlossen sein)
MP.x=MP.y=MAXINT;
//Ausrichtung an Eltern-Fenster: Client-Bereich, innen
W2=GetParent(W);
if (!W2) W2=GetDesktopWindow();
GetClientRect(W2,&RP);
MapWindowPoints(W2,0,(LPPOINT)&RP,2); // wie ClientToScreen beider Ecken
if (RP.top<R.bottom && R.top<RP.bottom) {
if (sleft &snap) AbsMin(MP.x,R.left -RP.left);
if (sright &snap) AbsMin(MP.x,R.right -RP.right);
}
if (RP.left<R.right && R.left<RP.right) {
if (stop &snap) AbsMin(MP.y,R.top -RP.top);
if (sbottom&snap) AbsMin(MP.y,R.bottom-RP.bottom);
}
//Ausrichtung an Geschwister: Ganze Fenster, außen
for (W2=GetWindow(W2,GW_CHILD); W2; W2=GetWindow(W2,GW_HWNDNEXT)) {
if (W2==W) continue; //Nicht das eigene Fenster benutzen!
if (!IsWindowVisible(W2)) continue;
if (IsIconic(W2)) continue;
GetClassName(W2,s,sizeof(s));
if (!lstrcmp(s,"#32772")) continue; //IconTitle
GetWindowRect(W2,&R2);
if (R2.top<R.bottom && R.top<R2.bottom) {
if (sleft &snap) AbsMin(MP.x,R.left -R2.right);
if (sright &snap) AbsMin(MP.x,R.right -R2.left);
}
if (R2.left<R.right && R.left<R2.right) {
if (stop &snap) AbsMin(MP.y,R.top -R2.bottom);
if (sbottom&snap) AbsMin(MP.y,R.bottom-R2.top);
}
//Ausrichtung an Geschwister: Eck-Kreuzungen bevorzugen
if (Abs(R.bottom-R2.top)<=SnapW
||Abs(R.top-R2.bottom)<=SnapW) {
if (sleft &snap) AbsMin(MP.x,R.left -R2.left);
if (sright &snap) AbsMin(MP.x,R.right -R2.right);
}
if (Abs(R.left-R2.right)<=SnapW
||Abs(R.right-R2.left)<=SnapW) {
if (stop &snap) AbsMin(MP.y,R.top -R2.top);
if (sbottom&snap) AbsMin(MP.y,R.bottom-R2.bottom);
}
}
//Schnappeffekt (Weite) prüfen
if (Abs(MP.x)>SnapW) MP.x=0;
if (Abs(MP.y)>SnapW) MP.y=0;
//Rechteck verändern
CopyRect(&R2,&R);
if (sleft &snap) R.left -=MP.x;
if (stop &snap) R.top -=MP.y;
if (sright &snap) R.right -=MP.x;
if (sbottom&snap) R.bottom-=MP.y;
//Sicherung, dass Fenster nicht unerreichbar herausrutscht
if (R.left >= RP.right) R.left =R2.left;
if (R.right<= RP.left) R.right=R2.right;
if (R.top <= RP.top-GetSystemMetrics(SM_CYCAPTION)) R.top=R2.top;
if (R.top >= RP.bottom) R.top=R2.top;
/* Zumindest Windows98 sorgt offenbar selbst dafür, dass aus MOVE
kein SIZE wird, wenn das Rechteck einseitig modifiziert wurde. */
}
LRESULT CALLBACK CbtHook(int Code, WPARAM wParam, LPARAM lParam) {
static BYTE snap=sleft|sright|stop|sbottom; //rutscht nach .shared: OK
LRESULT ret;
HWND W;
POINT P;
int HitCode;
ret=CallNextHookEx(Hook,Code,wParam,lParam);
switch (Code) {
case HCBT_SYSCOMMAND: switch (wParam&0xFFF0) {
case SC_MOVE: {
snap=sleft|sright|stop|sbottom; //alle 4 Seiten ziehen lassen
}break;
case SC_SIZE: {
snap=0;
GetCursorPos(&P); //funktioniert nur mit Maus!
W=WindowFromPoint(P);
if (!W) return ret;
HitCode=SendMessage(W,WM_NCHITTEST,0,MAKELPARAM(P.x,P.y));
switch (HitCode) {
case HTLEFT: snap=sleft; break;
case HTTOPLEFT: snap=sleft|stop; break;
case HTTOP: snap=stop; break;
case HTTOPRIGHT: snap=stop|sright; break;
case HTRIGHT: snap=sright; break;
case HTBOTTOMRIGHT:snap=sright|sbottom; break;
case HTBOTTOM: snap=sbottom; break;
case HTBOTTOMLEFT: snap=sleft|sbottom; break;
//default: MessageBeep(UINT(-1));
}
}break;
}break;
case HCBT_MOVESIZE: if (!(GetKeyState(VK_CONTROL)&0xFFFE)) {
AdjustRect((HWND)wParam,*(LPRECT)lParam,snap);
}
}
return ret;
}
extern "C" BOOL __stdcall _DllMainCRTStartup(
HINSTANCE hinstDLL, // DLL-Handle (=Basisadresse?)
DWORD fdwReason, // einer von 4 Gründen des Aufrufs
LPVOID lpvReserved) { // implizit-explizit-Flag
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
DisableThreadLibraryCalls(hinstDLL);
if (!Hook) {
SnapW=GetProfileInt("Windows","Snap",SnapW);
HookProcess=Hook=SetWindowsHookEx(WH_CBT,
CbtHook,hinstDLL,0);
}
}break;
case DLL_PROCESS_DETACH: {
if (HookProcess) UnhookWindowsHookEx(HookProcess);
}
}
return TRUE;
}
Detected encoding: ANSI (CP1252) | 4
|
|