Skip to content

Instantly share code, notes, and snippets.

@quark-zju
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quark-zju/11246861 to your computer and use it in GitHub Desktop.
Save quark-zju/11246861 to your computer and use it in GitHub Desktop.
Win32 TCP service to provide windows titles and their flashing status.
#!/usr/bin/env ruby
# Example ruby client of winlist-server.
HOST = '172.22.22.1'
PORT = 4015
require 'socket'
require 'timeout'
def get_flashing_window_list
Timeout.timeout(10) do
TCPSocket.new(HOST, PORT).read.force_encoding(Encoding::UTF_8).lines.select{|l| l.start_with? '*'}.map{|l| l[2..-2].split(' ', 2)} rescue nil
end rescue nil
end
notified = {}
while sleep 1
list = get_flashing_window_list
next unless list
# parse list
# list.lines.map
map = Hash[list]
map.each do |hwnd, title|
next if notified[hwnd]
notified[hwnd] = true
system 'notify-send', '-t', '0', '新闪动窗口', title
end
notified.delete_if {|hwnd| !map[hwnd]}
end
/*
Win32 TCP service to provide windows titles and their flashing status.
This file is POORLY written. Do not take it too seriously.
Example Usage:
telnet 10.0.2.2 4015 # 10.0.2.2 is vbox host
Trying 10.0.2.2...
Connected to 10.0.2.2.
Escape character is '^]'.
2016a 开始
* 910b8a Alice - Bob
48132e Win32Project1 (正在运行) - Microsoft Visual Studio Express 2013 for Windows Desktop
* 260416 我的手机
3d013c 无标题 - 记事本
7d0b30 下载
881354 C:\windows\system32\cmd.exe
10230 易信
220408 C:\windows\system32\cmd.exe
240fce Program Manager
Should compile under VC++ 2013 express.
Note: '*' indicates that window is flashing.
Note about security: client ip whitelist is hardcoded now.
*/
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cassert>
#include <ctime>
#include <concurrent_unordered_map.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "Ws2_32.lib")
#define PORT 4015
static UINT WM_SHELLHOOKMESSAGE;
using std::cout;
using std::wcout;
using concurrency::concurrent_unordered_map;
concurrent_unordered_map<HWND, clock_t> flashingWindowHwnds;
volatile SOCKET client;
void BeginThread();
// Enum window titles
BOOL CALLBACK enumWindowsCallback(HWND hwnd, LPARAM IParam) {
int l = GetWindowTextLengthW(hwnd) + 1;
// ignore invisible windows
LONG style = GetWindowLong(hwnd, GWL_STYLE);
if ((style & WS_VISIBLE) == 0) return TRUE;
// ignore empty title windows
if (l <= 1) return TRUE;
// Get window title
WCHAR *s;
s = (WCHAR *)calloc(l, sizeof(WCHAR));
l = GetWindowTextW(hwnd, s, l);
s[l] = 0;
wcout << s << L"\n";
// WCHAR -> UTF8
char *utf8Buf;
utf8Buf = (char *)calloc(1, l * 4 + 4);
WideCharToMultiByte(
CP_UTF8, /* CodePage */
0, /* dwFlags */
s, /* lpWideCharStr */
-1, /* cchWideChar (null terminated) */
utf8Buf, /* lpMultiByteStr */
l * 4 + 3, /* cbMultiByte */
NULL,
NULL
);
// Send window hwnd, title, flashing status to client
size_t resultBufSize = l * 4 + 128;
char *resultBuf = (char *)calloc(1, resultBufSize);
int flash = (flashingWindowHwnds.count(hwnd) > 0 && flashingWindowHwnds[hwnd]);
_snprintf(resultBuf, resultBufSize, "%c %x %s\n", flash ? '*' : ' ', hwnd, utf8Buf);
send(client, resultBuf, strlen(resultBuf), 0);
free(utf8Buf);
free(s);
free(resultBuf);
return TRUE;
}
void startEnumWindows() {
EnumWindows(enumWindowsCallback, 0);
}
// http://www.howsoftworks.net/windows/user-interface/registershellhookwindow.html
void SetShellHook(HWND hwndHook)
{
WM_SHELLHOOKMESSAGE = RegisterWindowMessage(TEXT("SHELLHOOK"));
assert(WM_SHELLHOOKMESSAGE);
BOOL ret = RegisterShellHookWindow(hwndHook);
assert(ret);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND clientHwnd = (HWND) lParam;
if (uMsg == WM_SHELLHOOKMESSAGE)
{
switch (wParam)
{
case HSHELL_FLASH:
flashingWindowHwnds[clientHwnd] = clock();
break;
case HSHELL_WINDOWACTIVATED:
if (flashingWindowHwnds.count(clientHwnd)) {
clock_t lastFlashAt = flashingWindowHwnds[clientHwnd];
// Some program will active their window as soon as flashing. Distinct it from maually activing by checking time.
if (lastFlashAt > 0 && clock() - lastFlashAt >= 500) {
flashingWindowHwnds[clientHwnd] = 0;
}
}
break;
case HSHELL_WINDOWDESTROYED:
if (flashingWindowHwnds.count(clientHwnd) && flashingWindowHwnds[clientHwnd]) {
flashingWindowHwnds[clientHwnd] = 0;
}
break;
case HSHELL_WINDOWCREATED:
break;
default:
break;
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
static TCHAR szAppName[] = TEXT("WindowListService");
MSG msg;
WNDCLASS wndclass;
BOOL bRet;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
bRet = RegisterClass(&wndclass);
assert(bRet);
HWND hWnd = CreateWindowExA(WS_EX_TOPMOST,
"WindowListService",
"WindowListService",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
1, 1,
NULL, NULL, hInstance, NULL);
assert(hWnd);
SetShellHook(hWnd);
BeginThread();
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// http://www.codeproject.com/Articles/1891/Beginning-Winsock-Programming-Simple-TCP-server
DWORD WINAPI ServerThread(LPVOID pParam)
{
//A SOCKET is simply a typedef for an unsigned int.
//In Unix, socket handles were just about same as file
//handles which were again unsigned ints.
//Since this cannot be entirely true under Windows
//a new data type called SOCKET was defined.
SOCKET server;
//WSADATA is a struct that is filled up by the call
//to WSAStartup
WSADATA wsaData;
//The sockaddr_in specifies the address of the socket
//for TCP/IP sockets. Other protocols use similar structures.
sockaddr_in local;
//WSAStartup initializes the program for calling WinSock.
//The first parameter specifies the highest version of the
//WinSock specification, the program is allowed to use.
int wsaret = WSAStartup(0x101, &wsaData);
//WSAStartup returns zero on success.
//If it fails we exit.
assert(wsaret == 0);
//Now we populate the sockaddr_in structure
local.sin_family = AF_INET; //Address family
local.sin_addr.s_addr = INADDR_ANY; //Wild card IP address
local.sin_port = htons((u_short)PORT); //port to use
//the socket function creates our SOCKET
server = socket(AF_INET, SOCK_STREAM, 0);
//If the socket() function fails we exit
assert(server != INVALID_SOCKET);
//bind links the socket we just created with the sockaddr_in
//structure. Basically it connects the socket with
//the local address and a specified port.
//If it returns non-zero quit, as this indicates error
int ret = bind(server, (sockaddr*)&local, sizeof(local));
assert(ret == 0);
//listen instructs the socket to listen for incoming
//connections from clients. The second arg is the backlog
ret = listen(server, 10);
assert(ret == 0);
//we will need variables to hold the client socket.
//thus we declare them here.
sockaddr_in from;
int fromlen = sizeof(from);
while (true)//we are looping endlessly
{
//accept() will accept an incoming
//client connection
client = accept(server, (struct sockaddr*)&from, &fromlen);
char * clientIp = inet_ntoa(from.sin_addr);
if (strcmp(clientIp, "172.22.22.2") == 0 || strcmp(clientIp, "127.0.0.1") == 0) {
startEnumWindows();
}
//close the client socket
closesocket(client);
}
//closesocket() closes the socket and releases the socket descriptor
closesocket(server);
//originally this function probably had some use
//currently this is just for backward compatibility
//but it is safer to call it as I still believe some
//implementations use this to terminate use of WS2_32.DLL
WSACleanup();
return 0;
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516%28v=vs.85%29.aspx
void BeginThread()
{
DWORD dwThreadId;
HANDLE hThread;
hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
ServerThread, // thread function name
NULL, // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
assert(hThread);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment