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.
429 lines
13 KiB
429 lines
13 KiB
#include "resource.h"
|
|
|
|
/*variables*/
|
|
UINT WM_TASKBAR = 0;
|
|
HWND Hwnd;
|
|
HMENU Hmenu;
|
|
NOTIFYICONDATA notifyIconData;
|
|
TCHAR szTIP[64] = TEXT("Snoopy.. \n Kicks Ass!");
|
|
const wchar_t* szClassName = L"Snoopy's System Tray Demo.";
|
|
|
|
|
|
|
|
/*procedures */
|
|
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
|
|
void minimize();
|
|
void restore();
|
|
void InitNotifyIconData();
|
|
int CaptureImage(HWND hWnd, const wchar_t* filename);
|
|
|
|
|
|
|
|
int WINAPI WinMain (HINSTANCE hThisInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpszArgument,
|
|
int nCmdShow)
|
|
{
|
|
/* This is the handle for our window */
|
|
MSG messages; /* Here messages to the application are saved */
|
|
WNDCLASSEX wincl; /* Data structure for the windowclass */
|
|
WM_TASKBAR = RegisterWindowMessageA("TaskbarCreated");
|
|
/* The Window structure */
|
|
wincl.hInstance = hThisInstance;
|
|
wincl.lpszClassName = szClassName;
|
|
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
|
|
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
|
|
wincl.cbSize = sizeof (WNDCLASSEX);
|
|
|
|
/* Use default icon and mouse-pointer */
|
|
wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
|
|
wincl.hIconSm = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
|
|
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
wincl.lpszMenuName = NULL; /* No menu */
|
|
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
|
|
wincl.cbWndExtra = 0; /* structure or the window instance */
|
|
wincl.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(255, 255, 255)));
|
|
/* Register the window class, and if it fails quit the program */
|
|
if (!RegisterClassEx (&wincl))
|
|
return 0;
|
|
|
|
/* The class is registered, let's create the program*/
|
|
Hwnd = CreateWindowEx (
|
|
0, /* Extended possibilites for variation */
|
|
szClassName, /* Classname */
|
|
szClassName, /* Title Text */
|
|
WS_OVERLAPPEDWINDOW, /* default window */
|
|
CW_USEDEFAULT, /* Windows decides the position */
|
|
CW_USEDEFAULT, /* where the window ends up on the screen */
|
|
544, /* The programs width */
|
|
375, /* and height in pixels */
|
|
HWND_DESKTOP, /* The window is a child-window to desktop */
|
|
NULL, /* No menu */
|
|
hThisInstance, /* Program Instance handler */
|
|
NULL /* No Window Creation data */
|
|
);
|
|
/*Initialize the NOTIFYICONDATA structure only once*/
|
|
InitNotifyIconData();
|
|
/* Make the window visible on the screen */
|
|
ShowWindow (Hwnd, nCmdShow);
|
|
|
|
/* register hotkey. 0x59 is 'y' so win+y or print *
|
|
* see: https://docs.microsoft.com/de-de/windows/desktop/inputdev/virtual-key-codes */
|
|
if (!RegisterHotKey(Hwnd, WM_HOTKEY_FREEZE, MOD_WIN, 0x59)
|
|
|| !RegisterHotKey(Hwnd, WM_HOTKEY_FREEZE, 0, 0x2c)) {
|
|
FatalAppExit(0, TEXT("Couldn't register hotkey!"));
|
|
}
|
|
|
|
/* Run the message loop. It will run until GetMessage() returns 0 */
|
|
while (GetMessage (&messages, NULL, 0, 0))
|
|
{
|
|
/* Translate virtual-key messages into character messages */
|
|
TranslateMessage(&messages);
|
|
/* Send message to WindowProcedure */
|
|
DispatchMessage(&messages);
|
|
}
|
|
|
|
// clean up here?
|
|
|
|
return messages.wParam;
|
|
}
|
|
|
|
|
|
/* This function is called by the Windows function DispatchMessage() */
|
|
|
|
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
if ( message==WM_TASKBAR && !IsWindowVisible( Hwnd ) )
|
|
{
|
|
minimize();
|
|
return 0;
|
|
}
|
|
|
|
switch (message) /* handle the messages */
|
|
{
|
|
case WM_ACTIVATE:
|
|
Shell_NotifyIcon(NIM_ADD, ¬ifyIconData);
|
|
break;
|
|
case WM_CREATE:
|
|
|
|
ShowWindow(Hwnd, SW_HIDE);
|
|
Hmenu = CreatePopupMenu();
|
|
AppendMenu(Hmenu, MF_STRING, ID_TRAY_EXIT, TEXT( "Exit The Demo" ) );
|
|
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
/*In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter
|
|
are used internally by the system. To obtain the correct result when testing the value of wParam,
|
|
an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.*/
|
|
|
|
switch( wParam & 0xFFF0 )
|
|
{
|
|
case SC_MINIMIZE:
|
|
case SC_CLOSE:
|
|
minimize() ;
|
|
return 0 ;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
// Our user defined WM_SYSICON message.
|
|
case WM_SYSICON:
|
|
{
|
|
|
|
switch(wParam)
|
|
{
|
|
case ID_TRAY_APP_ICON:
|
|
SetForegroundWindow(Hwnd);
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
if (lParam == WM_LBUTTONUP)
|
|
{
|
|
|
|
restore();
|
|
}
|
|
else if (lParam == WM_RBUTTONDOWN)
|
|
{
|
|
// Get current mouse position.
|
|
POINT curPoint ;
|
|
GetCursorPos( &curPoint ) ;
|
|
SetForegroundWindow(Hwnd);
|
|
|
|
// TrackPopupMenu blocks the app until TrackPopupMenu returns
|
|
|
|
UINT clicked = TrackPopupMenu(Hmenu,TPM_RETURNCMD | TPM_NONOTIFY,curPoint.x,curPoint.y,0,hwnd,NULL);
|
|
|
|
|
|
|
|
SendMessage(hwnd, WM_NULL, 0, 0); // send benign message to window to make sure the menu goes away.
|
|
if (clicked == ID_TRAY_EXIT)
|
|
{
|
|
// quit the application.
|
|
Shell_NotifyIcon(NIM_DELETE, ¬ifyIconData);
|
|
UnregisterHotKey(Hwnd, WM_HOTKEY_FREEZE);
|
|
PostQuitMessage( 0 ) ;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_HOTKEY_FREEZE:
|
|
{
|
|
restore();
|
|
}
|
|
break;
|
|
|
|
// intercept the hittest message..
|
|
case WM_NCHITTEST:
|
|
{
|
|
UINT uHitTest = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
|
|
if(uHitTest == HTCLIENT)
|
|
return HTCAPTION;
|
|
else
|
|
return uHitTest;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
|
|
minimize() ;
|
|
return 0;
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
|
|
PostQuitMessage (0);
|
|
break;
|
|
|
|
}
|
|
|
|
return DefWindowProc( hwnd, message, wParam, lParam ) ;
|
|
}
|
|
|
|
|
|
void minimize()
|
|
{
|
|
// hide the main window
|
|
ShowWindow(Hwnd, SW_HIDE);
|
|
}
|
|
|
|
|
|
void restore()
|
|
{
|
|
ShowWindow(Hwnd, SW_SHOW);
|
|
CaptureImage(Hwnd, L"file.bmp");
|
|
}
|
|
|
|
void InitNotifyIconData()
|
|
{
|
|
memset( ¬ifyIconData, 0, sizeof( NOTIFYICONDATA ) ) ;
|
|
|
|
notifyIconData.cbSize = sizeof(NOTIFYICONDATA);
|
|
notifyIconData.hWnd = Hwnd;
|
|
notifyIconData.uID = ID_TRAY_APP_ICON;
|
|
notifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
|
notifyIconData.uCallbackMessage = WM_SYSICON; //Set up our invented Windows Message
|
|
notifyIconData.hIcon = (HICON)LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1) ) ;
|
|
wcsncpy(notifyIconData.szTip, szTIP, sizeof(szTIP));
|
|
}
|
|
|
|
|
|
void getRaspiStorage(LPWSTR out) {
|
|
// GetLogicalDrives()
|
|
// for result
|
|
// if result.GetDriveType() == DRIVE_REMOVABLE
|
|
|
|
WCHAR myDrives[105];
|
|
WCHAR volumeName[MAX_PATH];
|
|
WCHAR fileSystemName[MAX_PATH];
|
|
DWORD serialNumber, maxComponentLen, fileSystemFlags;
|
|
UINT driveType;
|
|
|
|
if (!GetLogicalDriveStringsW(ARRAYSIZE(myDrives)-1, myDrives))
|
|
{
|
|
//wprintf(L"GetLogicalDrives() failed with error code: %lu\n", GetLastError());
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
for (LPWSTR drive = myDrives; *drive != 0; drive += 4)
|
|
{
|
|
driveType = GetDriveTypeW(drive);
|
|
|
|
if (driveType == DRIVE_REMOVABLE)
|
|
{
|
|
if (GetVolumeInformationW(drive, volumeName, ARRAYSIZE(volumeName), &serialNumber, &maxComponentLen, &fileSystemFlags, fileSystemName, ARRAYSIZE(fileSystemName)))
|
|
{
|
|
if (wcscmp(volumeName, L"SCREENSHOTS")) {
|
|
wcsncpy(drive, out, sizeof(out));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION: CaptureAnImage(HWND hWnd)
|
|
//
|
|
// PURPOSE: Captures a screenshot into a window and then saves it in a .bmp file.
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// Note: This sample will attempt to create a file called captureqwsx.bmp
|
|
//
|
|
// https://docs.microsoft.com/de-de/windows/desktop/gdi/capturing-an-image
|
|
|
|
int CaptureImage(HWND hWnd, const wchar_t* filename) {
|
|
HDC hdcScreen;
|
|
HDC hdcWindow;
|
|
HDC hdcMemDC = NULL;
|
|
HBITMAP hbmScreen = NULL;
|
|
BITMAP bmpScreen;
|
|
|
|
// Retrieve the handle to a display device context for the client
|
|
// area of the window.
|
|
hdcScreen = GetDC(NULL);
|
|
hdcWindow = GetDC(hWnd);
|
|
|
|
// Create a compatible DC which is used in a BitBlt from the window DC
|
|
hdcMemDC = CreateCompatibleDC(hdcWindow);
|
|
|
|
if(!hdcMemDC)
|
|
{
|
|
MessageBox(hWnd, L"CreateCompatibleDC has failed",L"Failed", MB_OK);
|
|
DeleteObject(hdcMemDC);
|
|
ReleaseDC(NULL,hdcScreen);
|
|
ReleaseDC(hWnd,hdcWindow);
|
|
return -1;
|
|
}
|
|
|
|
// Get the client area for size calculation
|
|
RECT rcClient;
|
|
GetClientRect(hWnd, &rcClient);
|
|
|
|
//This is the best stretch mode
|
|
SetStretchBltMode(hdcWindow,HALFTONE);
|
|
|
|
//The source DC is the entire screen and the destination DC is the current window (HWND)
|
|
if(!StretchBlt(hdcWindow,
|
|
0,0,
|
|
rcClient.right, rcClient.bottom,
|
|
hdcScreen,
|
|
0,0,
|
|
GetSystemMetrics (SM_CXSCREEN),
|
|
GetSystemMetrics (SM_CYSCREEN),
|
|
SRCCOPY))
|
|
{
|
|
MessageBox(hWnd, L"StretchBlt has failed",L"Failed", MB_OK);
|
|
DeleteObject(hdcMemDC);
|
|
ReleaseDC(NULL,hdcScreen);
|
|
ReleaseDC(hWnd,hdcWindow);
|
|
return -1;
|
|
}
|
|
|
|
// Create a compatible bitmap from the Window DC
|
|
hbmScreen = CreateCompatibleBitmap(hdcWindow, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
|
|
|
|
if(!hbmScreen)
|
|
{
|
|
MessageBox(hWnd, L"CreateCompatibleBitmap Failed",L"Failed", MB_OK);
|
|
DeleteObject(hbmScreen);
|
|
DeleteObject(hdcMemDC);
|
|
ReleaseDC(NULL,hdcScreen);
|
|
ReleaseDC(hWnd,hdcWindow);
|
|
return -1;
|
|
}
|
|
|
|
// Select the compatible bitmap into the compatible memory DC.
|
|
SelectObject(hdcMemDC,hbmScreen);
|
|
|
|
// Bit block transfer into our compatible memory DC.
|
|
if(!BitBlt(hdcMemDC,
|
|
0,0,
|
|
rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
|
|
hdcWindow,
|
|
0,0,
|
|
SRCCOPY))
|
|
{
|
|
MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK);
|
|
DeleteObject(hbmScreen);
|
|
DeleteObject(hdcMemDC);
|
|
ReleaseDC(NULL,hdcScreen);
|
|
ReleaseDC(hWnd,hdcWindow);
|
|
return -1;
|
|
}
|
|
|
|
// Get the BITMAP from the HBITMAP
|
|
GetObject(hbmScreen,sizeof(BITMAP),&bmpScreen);
|
|
|
|
BITMAPFILEHEADER bmfHeader;
|
|
BITMAPINFOHEADER bi;
|
|
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = bmpScreen.bmWidth;
|
|
bi.biHeight = bmpScreen.bmHeight;
|
|
bi.biPlanes = 1;
|
|
bi.biBitCount = 32;
|
|
bi.biCompression = BI_RGB;
|
|
bi.biSizeImage = 0;
|
|
bi.biXPelsPerMeter = 0;
|
|
bi.biYPelsPerMeter = 0;
|
|
bi.biClrUsed = 0;
|
|
bi.biClrImportant = 0;
|
|
|
|
DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight;
|
|
|
|
// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
|
|
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
|
|
// have greater overhead than HeapAlloc.
|
|
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize);
|
|
char *lpbitmap = (char *)GlobalLock(hDIB);
|
|
|
|
// Gets the "bits" from the bitmap and copies them into a buffer
|
|
// which is pointed to by lpbitmap.
|
|
GetDIBits(hdcWindow, hbmScreen, 0,
|
|
(UINT)bmpScreen.bmHeight,
|
|
lpbitmap,
|
|
(BITMAPINFO *)&bi, DIB_RGB_COLORS);
|
|
|
|
// A file is created, this is where we will save the screen capture.
|
|
HANDLE hFile = CreateFile(filename,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
// Add the size of the headers to the size of the bitmap to get the total file size
|
|
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
//Offset to where the actual bitmap bits start.
|
|
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);
|
|
|
|
//Size of the file
|
|
bmfHeader.bfSize = dwSizeofDIB;
|
|
|
|
//bfType must always be BM for Bitmaps
|
|
bmfHeader.bfType = 0x4D42; //BM
|
|
|
|
DWORD dwBytesWritten = 0;
|
|
WriteFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
|
|
WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
|
|
WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL);
|
|
|
|
//Unlock and Free the DIB from the heap
|
|
GlobalUnlock(hDIB);
|
|
GlobalFree(hDIB);
|
|
|
|
//Close the handle for the file that was created
|
|
CloseHandle(hFile);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|