Lzp729@Blog

道法自然

文本输出

By lzp729 on February 11, 2012

在以下任何事件发生时,向窗口过程都会受到一条WM_PAINT消息

  • 用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来
  • 用户调整窗口的大小(当窗口类型的设定为CS_HREDRAW和CS_VREDRAW时)
  • 程序调用ScollWindow或ScollDC函数滚动客户区时
  • 程序调用InvalidateRect或InvalidateRgn函数显式生成WM_PAINT消息

当客户区的一部分被临时覆盖时,Windows会试图保存被覆盖的这部分,以便将来恢复时使用,但并不是每次都会成功,在以下情况下有时会发送一条WM_PAINT消息

  • Windows关闭一个覆盖了部分窗口的对话框或消息框
  • 下拉菜单被拉下然后收回
  • 显示提示消息

少数情况下,Windows总是保存并恢复被覆盖区域,而不再发送WM_PAINT消息

  • 鼠标指针在客户区内移动
  • 在客户区内拖动图标

需要重新绘制的部分被称为“无效区域”或“更新区域”。Windows内部为每一个窗口都保存了一个“绘制信息结构”。这个结构保存着一个可以覆盖该无效区域的最小矩形的坐标和一个其他的信息。如果在窗口过程处理一条等候处理的WM_PAINT消息之前,客户区中的另一部分也失效了,那么Windows将计算出一个覆盖这两个失效部分的新的无效区域和无效矩形,并更新绘制信息结构中的数据。Windows不会在消息队列中放置多条WM_PAINT消息。

InvalidateRect函数强制使客户区中的一个矩形失效,可以通过GetUpdateRect函数获取这些坐标,在BeginPaint函数调用后,整个客户区会变成有效的,也可以用ValidateRect函数使一个区域有效,如果ValidateRect函数的调用使得整个客户区变得有效,那么消息队列中的WM_PAINT消息会被删除。

设备环境DC实际上是GDI内部维护的一个数据结构,对于视频显示,设备环境通常与屏幕上的一个特定的窗口相关联。程序必须在同一条消息中获取并释放DC,并且不能在两条消息中间传递DC,唯一的例外是通过CreateDC创建出来的。

    • 获取DC的方法1

在处理WM_PAINT消息时。窗口过程首先调用BeginPaint函数。这个函数通常会擦除无效区域的背景,并填充PAINTSTRUCT结构的各字段。函数的返回值就是DC。

对于PAINTSTRUCT,程序只能使用前三个字段hdc、fErase和rcPaint,其他的供Windows内部使用。大多数情况下,fErase被设置为false,意味着Windows在BeginPaint函数中已经擦除了无效区域的背景(如果想在窗口过程中自定义背景擦除方式,必需自己处理WM_ERASEBKGND消息)。Windows使用在窗口类型中定义的hbrBackground字段指定的画刷在擦除背景。

如果通过InvalidateRect函数来使矩形失效时,InvalidateRect函数的最后一个参数将指定背景是否擦除,如果设置为false,Windows将不擦除背景,同时在调用BeginPaint时,PAINTSTRUCT结构中的fErase被设置为true。

InvalidateRect中的fErase可理解为是否需要擦除背景,true时Windows会擦除。PAINTSTRUCT中的fErase可理解为通知用户背景是否需要擦除,如果是true,那么用户可以判断这个字段来手工擦除。则,在InvalidateRect中设置为true,即指定需要擦除,那么BeginPaint函数就会擦除,而通知用户会被设置为false,因为已经由Windows擦除了,所以不需要用户再次擦除。

PAINTSTRUCT结构的rcPaint字段是一个RECT,保存了无效矩形的坐标。

InvalidateRect(hwnd,NULL,TRUE);这个调用会使整个客户区无效,并使其后调用的BeginPaint擦除原有的背景。在使用从BeginPaint返回的DC时,Windows无论如何也不会在rcPaint定义的矩形之外绘制。

    • 获取DC的方法2

通过GetDC和ReleaseDC来获取的DC与BeginPaint获取的DC值不同。从GetDC返回的设备环境句柄中的裁剪区域是整个客户区,与无效矩形没有任何关系,GetDC也不会将无效区域有效化,必需由用户调用ValidateRect(hwnd,NULL);来使得整个客户区都有效。

而通过GetWindowDC获取的则是整个窗口区域,包括了标题栏,相应的程序必需要处理WM_NCPAINT(非客户区绘制消息)消息。

对于TextOut(hdc, x, y, psText, iLength)

  • 设备环境DC中的属性决定了文本显示的属性,包括颜色,字体,背景色等。文本的背景色与客户区的背景色不同,文本的背景色是指文本框的背景色。
  • x,y文本框左上角是相对于客户区左上角的坐标。默认的映射模式是MM_TEXT,即逻辑单位都是像素。
  • psText是字符串指针,iLength是字符串长度,TextOut不认为字符串以0结尾,如果psText是UNICODE,那么iLength是字符串字节数的一半。
  • TextOut使用的系统字体,在Windows启动后就不会改变,系统字体要求能够在显示器上起码显示25行80列字符。

GetSystemMetrics函数用来获取用户界面的尺寸,GetTextMetrics从dc中获取字体信息TEXTMETRIC。

除了上图中的重要的TEXTMETRIC字段外,还有
tmExtenalLeading,表示字体设计者建议的两行文字之间的空间大小,一般是0像素。
tmAveCharWidth,表示小写字符的加权平均宽度。一般大写字符的平均宽度是tmAveCharWidth的1.5倍。
tmMaxCharWidth,表示字体中最宽的字符的宽度。

消息处理函数更新为

int cxChar, cxCaps, cyChar;
char szBuffer[50];
case WM_CREATE:
          hdc = GetDC (hwnd) ;
 
          GetTextMetrics (hdc, &tm) ;
          cxChar = tm.tmAveCharWidth ;
          cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
          cyChar = tm.tmHeight + tm.tmExternalLeading ;
 
          ReleaseDC (hwnd, hdc);
          return 0 ;
case WM_PAINT :
          hdc = BeginPaint (hwnd, &ps) ;
		  j = NUMLINES;
          for (i = 0 ; i < 3; i++)
          {
               TextOut (hdc, 0, cyChar * i, TEXT("NAME"), 4);
               TextOut (hdc, 22 * cxCaps, cyChar * i, TEXT("Description"), 11);
               SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
               TextOut (hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer, wsprintf (szBuffer, TEXT ("Value"))) ;
               SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
          }
          EndPaint (hwnd, &ps) ;
          return 0 ;

其中tmPitchAndFamily的第1位表示该字体是否是等宽字体,1是等宽,0不是。
代码为TEXT(“NAME”)栏,保留了22个大写字母的宽度。
SetTextAlign (hdc, TA_RIGHT | TA_TOP)使得字符框的右上角与TextOut中指定的坐标右上角对齐,所以代码为TEXT(“Description”)和TEXT(“Value”)一共保留了40个小写字符的宽度。
最后SetTextAlign (hdc, TA_LEFT | TA_TOP)恢复默认对齐。

可以处理WM_SIZE消息来获取窗口大小的改变,此时消息的lParam的低位WORD是客户区宽度,高位WORD是高度。可以用WINDEF.H中的宏来获取。

#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0XFFFF))

两个宏都返回WORD值,即无符号整形,可以直接赋值给int类型以便使用。

在窗口长宽发生改变时会得到WM_SIZE消息,由于在窗口类型定义时指定CS_HREDRAW | CS_VREDRAW,所以在WM_SIZE后会有WM_PAINT消息。

static int cxClinet, cyClient;
case WM_SIZE:
          cxClient = LOWORD(lParam);
          cyClient = HIWORD(lParam);
          return 0 ;

cyClient / cyChar 表示客户区能够容纳的行数
cxClient / cxChar 表示一行大概能够容纳的小写字符数

Windows文档和头文件中的标识符都是从用户角度出发,向上滚动意味着移向文档的开始,向下滚动意味着移向文档的结束。客户区不包含滚动条的空间,滚动条的大小是确定的,可以通过GetSystemMetrics获取。

滚动条默认范围是0~100,可以通过GetScollRange和SetScollRange来获取和设置,其中参数iBar只有SB_VERT和SB_HORZ两种取值。 滚动条滑块的位置可以通过GetScollPos和SetScollPos来获取和设置。

滚动的使用需要Windows和程序共同维护,Windows主要负责

  • 处理滚动条中的所有鼠标消息
  • 当用户单击滚动条时,提供一种反向显示的闪烁
  • 当用户拖住滑块时,在滚动条内移动滑块
  • 向拥有滚动条的窗口的窗口过程发送滚动条消息

程序需要负责:

  • 初始化滚动条的范围和位置
  • 处理传递给窗口过程的滚动条消息
  • 更新滑块位置
  • 根据滚动条的变化更新客户区的内容

用户单击滚动条或拖动滑块时,Windows向窗口过程发送WM_VSCROLL消息或者WM_HSCROLL消息,当滚动条是窗口的一部分时,可以忽略lParam参数,wParam参数的低位字代表鼠标在滚动条上的动作,称为“通知码”,由SB开头的标识符。

  • 在滚动条的不同部分按住鼠标不放,程序可能收到多条滚动条消息,当松开鼠标键时,通知码为SB_ENDSCOLL,通常可以忽略此通知码的消息。Windows并不会自己改变滑块的位置,需要程序用SetScollPos来设置。
  • 将鼠标放在滑块上然后按下鼠标键,可以移动滑块。此时通知码为SB_THUMBTRACK和SB_THUMBPOSITION,当通知码是SB_THUMBTRACK时,wParam的高位字是滑块的当前位置,当通知码是SB_THUMBPOSITION时,wParam高位字是用户松开鼠标时,滑块的最终位置,其他通知码时,wParam高位字无意义。
  • Windows会在发送消息码为SB_THUMBTRACK的消息的同时移动滑块,但是在用户松开鼠标时回到原来位置,除非程序用SetScollPos设置最终位置。
  • 一般程序只处理SB_THUMBTRACK和SB_THUMBPOSITION中的一个,处理SB_THUMBTRACK需要适时更新客户区,处理SB_THUMBPOSITION需要在用户停止移动后更新客户区。
  • SB_TOP,SB_BOTTOM,SB_LEFT和SB_RIGHT表示滑块到达了最小或者最大值。
  • 由于wParam的高位字是16位,所以如果滚动条范围用32位整数表示的话,那么可能会出现问题,此时应该用GetScollInfo函数来获取滑块位置。
#define WINVER 0x0500
#define NUMLINES 75
 
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
 
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
 
	static TCHAR szAppName[] = TEXT("SysMets");
	HWND hwnd;
	MSG msg;
 
	WNDCLASS wndclass;
	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 = TEXT("MainWindow");
 
	if (!RegisterClass(&wndclass))
	{
		MessageBox (NULL, TEXT("Program requires Windows NT"), szAppName, MB_ICONERROR);
		return 0;
	}
 
	hwnd = CreateWindow(TEXT("MainWindow"),szAppName,
		WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
		CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
		NULL,NULL,hInstance,NULL);
 
	ShowWindow(hwnd,iCmdShow);
	UpdateWindow(hwnd);
 
	while(GetMessage(&msg,NULL,0,0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
 
	return msg.wParam;
};
 
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	static UINT cxChar,cxCaps,cyChar,cxClients,cyClients,uiMaxWidth;
 
	HDC hdc;
	PAINTSTRUCT ps;
	SCROLLINFO si;
	TEXTMETRIC tm;
 
	int iVertPos, iHorzPos, iPaintBeg, iPaintEnd, i,x,y;
	TCHAR szBuffer[20];
 
	switch(message)
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
 
		ZeroMemory(&tm,sizeof tm);
		GetTextMetrics(hdc,&tm);
		cxChar = tm.tmAveCharWidth;
		cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
		cyChar = tm.tmHeight + tm.tmExternalLeading;
 
		ReleaseDC(hwnd,hdc);
 
		uiMaxWidth = 40 * cxChar + 22 * cxCaps;
 
		return 0;
 
	case WM_SIZE:
		cxClients = LOWORD(lParam);
		cyClients = HIWORD(lParam);
 
		ZeroMemory(&si,sizeof si);
		si.cbSize = sizeof si;
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = NUMLINES - 1;
		si.nPage = cyClients / cyChar;
		SetScrollInfo(hwnd,SB_VERT,&si,true);
 
		ZeroMemory(&si,sizeof si);
		si.cbSize = sizeof si;
		si.fMask = SIF_RANGE | SIF_PAGE;
		si.nMin = 0;
		si.nMax = uiMaxWidth / cxChar + 2;
		si.nPage = cxClients / cxChar;
		SetScrollInfo(hwnd,SB_HORZ,&si,true);
 
		return 0;
 
	case WM_VSCROLL:
 
		ZeroMemory(&si, sizeof si);
		si.cbSize = sizeof si;
		si.fMask = SIF_ALL;
		GetScrollInfo(hwnd,SB_VERT,&si);
 
		iVertPos = si.nPos;
		switch (LOWORD(wParam))
		{
		case SB_TOP:
			si.nPos = si.nMin;
			break;
		case SB_BOTTOM:
			si.nPos = si.nMax;
			break;
		case SB_LINEUP:
			si.nPos -= 1;
			break;
		case SB_LINEDOWN:
			si.nPos += 1;
			break;
		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;
		case SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;
		case SB_THUMBTRACK:
			si.nPos = si.nTrackPos;
			break;
 
		default:
			break;
		}
 
		si.fMask = SIF_POS;
		SetScrollInfo(hwnd,SB_VERT,&si,true);
		GetScrollInfo(hwnd,SB_VERT,&si);
 
		if (si.nPos != iVertPos)
		{
			ScrollWindow(hwnd,0,cyChar * (iVertPos - si.nPos), NULL,NULL);
			UpdateWindow(hwnd);
		}
 
		return 0;
 
	case WM_HSCROLL:
		ZeroMemory(&si, sizeof si);
		si.cbSize = sizeof si;
		si.fMask = SIF_ALL;
		GetScrollInfo(hwnd,SB_HORZ,&si);
 
		iHorzPos = si.nPos;
		switch (LOWORD(wParam))
		{
		case SB_TOP:
			si.nPos = si.nMin;
			break;
		case SB_BOTTOM:
			si.nPos = si.nMax;
			break;
		case SB_LINEUP:
			si.nPos -= 1;
			break;
		case SB_LINEDOWN:
			si.nPos += 1;
			break;
		case SB_PAGEUP:
			si.nPos -= si.nPage;
			break;
		case SB_PAGEDOWN:
			si.nPos += si.nPage;
			break;
		case SB_THUMBTRACK:
			si.nPos = si.nTrackPos;
			break;
 
		default:
			break;
		}
 
		si.fMask = SIF_POS;
		SetScrollInfo(hwnd,SB_HORZ,&si,true);
		GetScrollInfo(hwnd,SB_HORZ,&si);
 
		if (si.nPos != iHorzPos)
		{
			ScrollWindow(hwnd,cxChar * (iHorzPos - si.nPos),0, NULL,NULL);
			UpdateWindow(hwnd);
		}
 
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hwnd,&ps);
 
		ZeroMemory(&si,sizeof si);
 
		si.fMask = SIF_POS;
		GetScrollInfo(hwnd,SB_VERT,&si);
		iVertPos = si.nPos;
 
		si.fMask = SIF_POS;
		GetScrollInfo(hwnd,SB_HORZ,&si);
		iHorzPos = si.nPos;
 
		iPaintBeg = max (0, iVertPos + ps.rcPaint.top / cyChar) ;
		iPaintEnd = min (NUMLINES - 1,
					iVertPos + ps.rcPaint.bottom / cyChar) ;
 
		for (i = iPaintBeg ; i <= iPaintEnd ; i++)
		{
			x = cxChar * (1 - iHorzPos) ;
			y = cyChar * (i - iVertPos) ;
 
			TextOut (hdc, x, y,
					szBuffer,wsprintf (szBuffer, TEXT ("Name%d"),i)) ;
 
			TextOut (hdc, x + 22 * cxCaps, y,
					szBuffer,wsprintf (szBuffer, TEXT ("Description%d"),i)) ;
 
			SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
 
			TextOut (hdc, x + 22 * cxCaps + 40 * cxChar, y,
				szBuffer,wsprintf (szBuffer, TEXT ("Value%d"),i)) ;
 
			SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
		}
 
		EndPaint(hwnd,&ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd,message,wParam,lParam);
}

上面的代码几乎涵盖了文本输出中滚动条的各种用法。

  • 指定WS_HSCROLL和WS_VSCROLL表明该窗口将使用竖直和水平滚动条。
    hwnd = CreateWindow(TEXT("MainWindow"),szAppName, WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL);
  • 程序监听WM_CREATE消息,并且在窗口创建时,获取当前设备环境中字体的相关设置。
    程序监听WM_SIZE消息,并且根据窗口大小的变化,记录客户区的大小,并设置滚动条的新位置和滚动块的大小。
    程序监听多种通知码的WM_VSCROLL和WM_HSCROLL消息,并且设置滚动块的新位置,通过ScrollWindow函数滚动客户使得被滚动的区域失效而产生一条WM_PAINT消息。
  • iPaintBeg和iPaintEnd推算出需要被重绘的输出行,以此来加快重绘的过程。
    iPaintBeg = max (0, iVertPos + ps.rcPaint.top / cyChar);
    iPaintEnd = min (NUMLINES - 1, iVertPos + ps.rcPaint.bottom / cyChar);
  • x和y推算出正在被重绘的行的起始位置,可能出现负值。
    x = cxChar * (1 - iHorzPos);
    y = cyChar * (i - iVertPos);

Posted in API, Windows开发, 代码人生 | Tagged API, TextOut, Windows开发, 文本输出 | Leave a response

本地加密代理通道及相关应用Reloaded

By lzp729 on September 20, 2011

最近镇里的局域网访问google的所有服务速度暴慢, 有木有啊!!!
连基本的google搜索都在坑爹啊!!!
至于你们能不能忍, 至少哥不能忍了啊!!! hold不住了哇!!!

开始发飙了啊, 继上次发飙的利用SSH建立windows本地加密代理服务, 现在感觉还是不够方便,不太实用, 有些猥琐, 比较复杂, 所以这次发飙就主要为改善用户体验, 虽然即时可能用户只有偶一个淫…

主要的问题列一下:

  • 会被杀毒软件判断为病毒
  • SSH帐号是共享的, 每次改密码都得给好多朋友更新, 太麻烦
  • iphone之类的设备没法用
  • 创建本地代理服务太复杂, 一定时间后断线了不能自动重连

大概就这些了, 相对root cause和fix也列一下.

  • 会被杀毒软件判断为病毒
    root cause – 是原来创建的本地SSH代理的程序是用多个exe(putty.exe, plink.exe和batch脚本)一起打包, 自动解包运行来启动的, 这种behave会被杀毒软件标记为间谍软件的行为.
    fix – 现在我直接把相关程序的source拿来改掉, customized成为直接连接我的服务器的客户端, 并内置了帐号密码, 这样就不存在解包和自动运行的behave了, 而且内置帐号之后也稍微安全一点, 只是一点点, 因为只有静态de一下就可以看到用户名和密码了, 所以在服务端也有相关的权限设置配合.
  • SSH帐号是共享的
    root cause – NA
    fix – 这次直接给每个人提供一个单独的帐号了, 所以再有泄露的话也方便K人, 而不用改密码了
  • iphone之类的设备没法用
    root cause – 因为ios在没有jail break的情况下只有通过VPN翻墙, 而SSH代理和VPN是两码事
    fix – 这次提供了PPTP和L2TP两种模式的VPN给大家免费使用, 速度绝壁不坑爹滴. 当然这个VPN也可以在电脑上使用. 后面会谈谈VPN和SSH代理的异同
  • 创建本地代理服务太复杂,一定时间后断线了不能自动重连
    root cause – NA
    fix – 不建什么代理服务了, 麻烦的要死, 写了个脚本做进程监控, 下文会提到

对于VPN帐号和新的SSH客户端的话, 以前一直在用我这个的人应该都已经拿到了, 谁要需要的话联系我咯
申请PPTP/L2TP VPN帐号,点这里
申请本地SSH代理客户端,点这里

比较下VPN和SSH代理

  • VPN最方便, 而且只要支持PPTP和L2TP的系统都能用, VPN可以直接把电脑的所有网络访问全部导向到墙外, 但是这样一来在公司用的话就不方便了, 因为VPN网络不在公司的内网
  • SSH代理就是本地的SOCKS5代理, 所以需要自己设置网络软件的代理, 对于浏览器而言, 当然可以配合使用一些插件, 下面会说说chrome+Proxy Switchy的使用方式.

再看看本地代理进程监视怎么搞. 我给的本地代理的客户端就是一个exe, 比如user.exe, 下面给进程监控的vbs代码
把下面的代码保存为vbs格式, 和我给的exe放在同一个目录下, 双击这个vbs就会提示自动启动user.exe了, 如果出现超时断开的情况, 会提示自动重连, 要手动停止代理进程的话就再手动运行一次这个脚本. code就在哪里, 实现方式自己看咯

DIM sServiceName
sServiceName = "lzp729.exe"  ' 这是唯一需要改的位置, 就是我给的那个exe的名字, 如果这个vbs和exe不在同一目录, 就给出完整路径, 这个脚本在win7 sp1 64bit 测试通过

FUNCTION fGetProcessCount(sPrcs)
 
	DIM ret
	SET oWMI = GetObject("winmgmts:{impersonationlevel=impersonate}!\\.\root\cimv2")
	SET oPrcses = oWMI.execquery("select * from win32_process")
 
	ret = 0
	FOR EACH oPrcs in oPrcses 
		IF STRCOMP(UCASE(oPrcs.Name),UCASE(sPrcs)) = 0 THEN
 
			ret = ret + 1
 
		END IF
	NEXT
 
	SET oPrcs = NOTHING
	SET oPrcses = NOTHING
	SET oWMI = NOTHING
	fGetProcessCount = ret
 
END FUNCTION
 
FUNCTION fStartProcess(sPrcs)
 
	SET oShell = CreateObject("WScript.Shell")
	oShell.Run sServiceName,0,true
	SET oShell = NOTHING
 
END FUNCTION
 
FUNCTION fKillAllPrcsInstance(sPrcs)
 
	DIM ret
	SET oWMI = GetObject("winmgmts:{impersonationlevel=impersonate}!\\.\root\cimv2")
	SET oPrcses = oWMI.execquery("select * from win32_process")
 
	ret = 0
	FOR EACH oPrcs in oPrcses 
		IF STRCOMP(oPrcs.Name,sPrcs) = 0 THEN
 
			oPrcs.Terminate
 
		END IF
	NEXT
 
	SET oPrcs = NOTHING
	SET oPrcses = NOTHING
	SET oWMI = NOTHING
 
	fKillAllPrcsInstance = ret
 
END FUNCTION
 
 
FUNCTION fSetManualQuit(bManualQuit)
 
	DIM oFS, sManualQuitLock
 
	sManualQuitLock = sServiceName&".lck"
 
	IF bManualQuit = TRUE THEN
 
		SET oFS = CreateObject("Scripting.FileSystemObject")
		oFS.OpenTextFile(sManualQuitLock,2,TRUE).Close
		SET oFS = NOTHING
 
	ELSE
 
		IF fGetManualQuit = TRUE THEN
 
			SET oFS = CreateObject("Scripting.FileSystemObject")
			oFS.DeleteFile sManualQuitLock
			SET oFS = NOTHING
 
		END IF
	END IF
 
END FUNCTION
 
FUNCTION fGetManualQuit()
 
	DIM oFS, sManualQuitLock
 
	sManualQuitLock = sServiceName&".lck"
 
	SET oFS = CreateObject("Scripting.FileSystemObject")
 
	fGetManualQuit = oFS.FileExists(sManualQuitLock)
 
	SET oFS = NOTHING
 
END FUNCTION
 
 
DIM oShell, nCount
 
nCount = fGetProcessCount(sServiceName)
 
fSetManualQuit(FALSE)
 
DO WHILE TRUE
 
	IF nCount = 0 THEN
 
		IF fGetManualQuit = TRUE THEN
 
			fSetManualQuit(FALSE)
			EXIT DO
 
		ELSE
 
			IF Msgbox("Process " & sServiceName & " not existing, start it now?", vbYesNo, "Process Daemon") = vbYes THEN
 
				fStartProcess(sServiceName)
 
			ELSE
 
				EXIT DO
 
			END IF
 
		END IF
 
	ELSE
 
		IF Msgbox("Process " & sServiceName & " existing, terminate it now?", vbYesNo, "Process Daemon") = vbYes THEN
 
			fKillAllPrcsInstance(sServiceName)
			fSetManualQuit(TRUE)
 
		END IF
 
		EXIT DO		
 
	END IF
 
	WScript.Sleep 3000
 
LOOP

VPN的设置和使用就不多说了, 唯一的就是如果用L2TP的话, 认证方式是pre key, 密码有帐号的人都知道, 这里就不暴了, 省的被封

最后chrome + proxy switchy的配置
step1: 在chrome中安装proxy switchy的扩展
step2: 在proxy switchy中设置一个代理, 我的本地SSH代理是打开的本地8888端口, 所以完整的连接描述是socks5@127.0.0.1:8888, 自己设置咯
step3: 在proxy switchy中添加一条规则, 凡是url parttern符合*.google.*的就使用在step2中设置的代理, 当然你也可以用proxy switchy切换浏览器的默认代理, 注意这个切换不限于chrome, IE和使用IE的代理网络程序也会被设置, 不过由于是socks的代理, 不仅仅是http代理, 所以都能用
step4: 把proxy switchy设置为auto switch mode

最后回答某淫的一个问题, 为什么我不直接开个socks5的服务器, 这样直接连就完了, 现在这样还需要本地启动个程序来打开本地代理, 很麻烦.
回答是这个连接客户端有几个很不错的benefit

  • 这个本地的代理程序从建立到服务器的SSH的通道开始就是完全加密的, 其中翻过的一切防火墙,甚至包括我都不知道你到底通过代理做了什么, 而直接开socks服务不一样, 沿途的围墙都知道你在连socks5的代理, 而且你通过代理去了哪里, 做了什么, 这些墙们都看的一清二楚
  • 这个程序会对TCP socket和正文做一定的压缩, 而且压缩和解压都是自动完成的, 而且基本没有CPU消耗, 这有助于提高网速, 甚至理论可能, 你的带宽是2M, 在假设压缩比是25%的情况下, 你的下载速度可以达到2.5M
  • socks代理太容易被封了, 而且如果做开放代理的话, 我没法控制用户数量, 导致QoS下降, 如果做需要用户认证的代理的话, 又怕人家爆我的密码… 关键是socks服务器IP太容易被GFW了

就这样, 晚安

Posted in General technic | Tagged GFW, SSH, 代理, 服务, 翻墙, 进程监视, 进程重启 | 2 Responses

窗口和消息

By lzp729 on September 6, 2011

#include <windows.h>
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	static TCHAR szAppName[] = TEXT ("HelloWin") ;
 
	HWND   hwnd ;
	MSG    msg ;
	WNDCLASS wndclass ;
 
	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 ;
 
    if (!RegisterClass (&wndclass))
    {
		MessageBox(NULL, TEXT ("Windows and Message"), szAppName, MB_ICONERROR) ;
		return -1;
    }
 
    hwnd = CreateWindow( szAppName,  // window class name
		TEXT ("The Hello Program"),  // window caption
		WS_OVERLAPPEDWINDOW,         // window style
		CW_USEDEFAULT,               // initial x position
		CW_USEDEFAULT,               // initial y position
		CW_USEDEFAULT,               // initial x size
		CW_USEDEFAULT,               // initial y size
		NULL,                        // parent window handle
		NULL,                        // window menu handle
		hInstance,                   // program instance handle
		NULL) ;                      // creation parameters
 
    ShowWindow (hwnd, iCmdShow) ;    
    UpdateWindow (hwnd) ;
 
    while (GetMessage (&msg, NULL, 0, 0))
    {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
    }
    return msg.wParam;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect ;
 
	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint (hwnd, &ps);
		GetClientRect (hwnd, &rect);
		DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
		EndPaint (hwnd, &ps);
		return 0 ;
	case WM_DESTROY:
		PostQuitMessage (0);
		return 0;        
	}
	return DefWindowProc (hwnd, message, wParam, lParam);
}
前缀常量
CS类风格 Class Style
CW创建窗口 Create Window
DT文本绘制 Draw Text
IDI图标ID ID Icon
IDC光标ID ID Cursor
MB消息框 Message Box
SND声音 Sound
WM窗口消息 Window Message
WS窗口风格 WIndow Style

UINT表示unsigned int. 在16位下, WPARAM表示WORD(16b), LPARAM表示LONG(32b), 在32位下, WPARAM表示UNIT(32b), LPARAM仍然是LONG(32b)

WNDCLASS wndclass; // 在Windows中, 窗口都是基于某个窗口类创建的, 所以先定义要用的窗口类.

wndclass.style = CS_HREDRAW | CS_VREDRAW; // 设置这个窗口类的风格, CS_HREDRAW和CS_VREDRAW 表示窗口长或宽发生变化将导致窗口被重绘.

wndclass.lpfnWndProc = WndProc ; // 指定义窗口类的消息处理函数, 该函数必需符合LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ; // 用于在结构中保留一些额外的空间共用户使用

wndclass.hInstance = hInstance ; // 设置这个窗口类的应用程序实例句柄, 与WinMain第一参数相同.

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; // 设置默认图标
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; // 设置默认光标

wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ; // 获取Windows标准的白色笔刷

wndclass.lpszMenuName = NULL ; // 设置menu句柄, 此例中没有menu

wndclass.lpszClassName= szAppName ; // 该窗口类的名字,创建窗口通过该名字查找窗口类

hwnd = CreateWindow( szAppName, // 根据szAppName找到已经注册的窗口类
TEXT (“The Hello Program”), // 以”Windows and Message”为caption来创建窗口
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // 父窗口句柄, 如果是顶级窗口, 则设为NULL
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters

ShowWindow (hwnd, iCmdShow) ; // 负责将窗口显示在屏幕中, 并以wndclass.hbrBackground笔刷在擦除窗口背景.

UpdateWindow (hwnd) ; // 通过想窗口消息处理程序(WndProc)发送一条WM_PAINT消息而完成.

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
这里就是Windows API编程中所谓的消息循环.

GetMessage (&msg, NULL, 0, 0) // 后三个参数都设为NULL或0, 表示要获取所有消息
msg的类型为MSG, 定义为
typedef struct tagMSG
{
HWND hwnd; // 消息所指向的窗口句柄, 即CreateWindow所返回的句柄
UINT message; // 消息ID,定义在WINUSER.H中
WPARAM wParam; // 32b参数
LPARAM lParam; // 32b参数
DWORD time; // 消息进入消息队列的时间
POINT pt; // 消息进入消息队列时鼠标指针的位置所标
}MSG, * PMSG;
typedef struct POINT tagPOINT
{
LONG x;
LONG y;
}POINT, * PPOINT;
GetMessage()函数从该窗口的消息队列中获取一条消息, 并用该消息的属性填充msg结构.
TranslateMessage()函数对msg进行一定的加工(进行某些键盘消息的转换)
DispatchMessage()函数将msg返回给Windows, Windows将调用该msg的hwnd所对应窗口类中所定义窗口消息处理函数(WndProc).

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) // 窗口消息处理函数
该函数被Windows调用, 调用参数由消息循环中所捕获的msg所指定.

WM_PAINT消息极为重要, 当窗口的客户区的部分或者全部”无效”且必须更新时, 该窗口将得到此消息, 由于wndclass.style的设置, 当窗口尺寸发生变化时, 整个窗口会被宣布无效, 则也会触发此消息.对WM_PAINT消息的处理几乎总是由hdc = BeginPaint(hwnd, &ps)开始, BeginPaint()函数将用wndclass.hbrBackground笔刷擦除客户区, EndPaint()函数释放hdc, 这两个函数将使得客户区变为有效.

更改窗口的大小会触发WM_SIZE消息, 此消息的wParam字段可为SIZE_RESTORE, SIZE_MINIMIZED, SIZE_MAXIMIZED, SIZE_MAXSHOW或SIZE_MAXHIDE, lParam字段包含新的窗口大小信息, 可用相关的宏从lParam中获取SIZE.

WM_DESTROY消息表示用户选择了关闭窗口, 标准的处理方式就是PostQuitMessage(0), 该函数将插入一个WM_QUIT消息, GetMessage()函数只对WM_QUIT消息会返回0值, 于是就退出了消息循环, 最后的return msg.wParam就会向Windows返回当前捕获的msg(也就是WM_QUIT)的wParam的值, 该值由PostQuitMessage()的函数来指定.

当用户选择关闭窗口时, Windows会发送一条WM_SYSCOMMAND消息, 消息处理函数(由于没有case WM_SYSCOMMAND)WndProc()会交给DefWindowProc()处理, DefWindowProc()函数发现SYSCOMMAND是关闭后, 会发送一条WM_CLOSE消息, 同样被WndProc()转交给DefWindowProc(), DefWindowProc()函数发现是WM_CLOSE后, 会调用DestroyWindow()函数, DestryWindow()函数会使Windows发送一条WM_QUIT消息, 最终被WndProc捕获, 并通过PostQuitMessage()函数来处理.

消息分为队列消息和非队列消息, 对于队列消息, Windows将该消息插入该窗口的消息队列中, 由消息循环通过GerMessage()函数主动获取, 此过程是Post消息, 对于非队列消息, Windows会直接调用该窗口的WndProc函数, 此过程是Send消息.
队列消息主要由用户的输入产生, 包括WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_MOUSEMOVE, WM_LBUTTONDOWN等, WM_TIMER, WM_PAINT, WM_QUIT也是队列消息.
非队列消息包括队列消息以外的所有消息, 通常是由Windows函数引起的, 例如CreateWindow()函数产生WM_CREATE消息, ShowWindow()函数产生WM_SIZE和WM_SHOWWINDOW消息, UpdateWindow()函数产生WM_PAINT消息.
键盘或鼠标输出的队列消息, 也能产生非队列消息, 例如键盘或鼠标选择某个菜单项时, 最终会产生的WM_COMMAND消息是一个非队列消息.

所有消息都是按照次序由WndProc依次处理的, 消息循环和窗口过程不是并发运行的, DispatchMessage()函数只有在WndProc返回后才会返回才会继续下一次消息循环, 如果在WndProc内部产生新的消息, 那么必须在新的消息处理完毕返回后, 本消息的处理才会继续. 例如UpdateWindow()函数只有在WM_PAINT的处理完成后才会返回. 这意味着WndProc()函数必需是可递归执行的. 如果对某消息的处理时间消耗很大, 则应使用多线程.

Posted in API, Windows开发, 代码人生 | Tagged API, Windows开发, 消息循环 | Leave a response

教你如何从官网找到Windows Live 2011软件包的离线完整版的下载路径

By lzp729 on July 10, 2011

额。。。 好吧,我是个疯狂的软件新版跟随者和狂热的安装程序收集者。 -_-

今天Windows live 2011更新到新版15.4.3538.0513,当然更新,去官网下载,得到一个1M多点的wlsetup-web.exe程序,看大小就知道是要在线安装的,不爽,删之,把live.com网站翻了个边,没有找到记忆中的完整版下载的入口,无奈,小探索了下,发现了从官网找离线安装程序的办法,共享之。

从这里开始吧,打开http://explore.live.com/download-windows-live,可以选你要下载的语言,我选英文,你们自便。点English后会直接开始下载wlsetup-web.exe,当然这不是我要的,取消,复制下来English这个链接的地址是

http://g.live.com/1rewlive4-web/en/wlsetup-web.exe??WLI=1&WLXID=0d769581-fba3-4a13-8c0d-c3172ab2baf7&RID=00ef31a210c&TID=1310237640105&lid=

开始构造了,把后面那些记录下载量的东西都删掉得到

http://g.live.com/1rewlive4-web/en/wlsetup-web.exe

然后吧web换成all,得到

http://g.live.com/1rewlive4-all/en/wlsetup-all.exe

扔进迅雷,2分钟后下载完成,额。。。我是10M的

Posted in General technic | Tagged 15.4.3538.0513, windows live 2011, wlsetup-all, 完整, 离线 | 2 Responses

UNICODE简介

By lzp729 on June 6, 2011

  • 美国信息交换标准码(ASCII:American Standard Code for Information Interchange)起始于50年代后期,最后完成于1967年。有26个小写字母、26个大写字母、10个数字、32个符号、33个句柄和一个空格,总共128个字符码,共7位长。ASCII有许多优点。例如,26个字母代码是连续的;大写字母和小写字母可通过改变一位数据而相互转化;10个数字的代码可从数值本身方便地得到。
  • 最初的IBM扩展字符集包括某些带重音的字符和一个小写希腊字母表(在数学符号中非常有用),还包括一些块型和线状图形字符。附加的字符也被添加到ASCII控制字符的编码位置,这是因为大多数控制字符都不是拿来显示用的。
  • Windows字符集被称作「ANSI字符集」。ANSI草案和ISO标准最终成为ANSI/ISO 8859-1-1987,即「American National Standard for Information Processing-8-Bit Single-Byte Coded Graphic Character Sets-Part 1: Latin Alphabet No 1」,通常也简写为「Latin 1」。

    空方框表示该位置未定义字符。这与ANSI/ISO 8859-1的最终定义一致。ANSI/ISO 8859-1仅显示了图形字符,而没有控制字符,因此没有定义DEL。此外,代码0xA0定义为一个非断开的空格(这意味着在编排格式时,该字符不用于断开一行),代码0xAD是一个软连字符(表示除非在行尾断开单词时使用,否则不显示)。此外,ANSI/ISO 8859-1将代码0xD7定义为乘号(*),0xF7为除号(/)。Windows中的某些字体也定义了从0×80到0x9F的某些字符,但这些不是ANSI/ISO 8859-1标准的一部分。
  • MS-DOS 3.3(1987年4月发行)向IBM PC用户引进了代码页(code page)的概念,Windows也使用此概念。代码页定义了字符的映像代码。最初的IBM字符集被称作代码页437,或者「MS-DOS Latin US)。代码页850就是「MS-DOS Latin 1」,它用附加的带重音字母(但不是Latin 1 ISO/ANSI标准)代替了一些线形字符。其它代码页被其它语言定义。最低的128个代码总是相同的;较高的128个代码取决于定义代码页的语言。
  • 双字节字符集(DBCS:double-byte character set)。DBCS从256代码开始,就像ASCII一样。与任何行为良好的代码页一样,最初的128个代码是ASCII。然而,较高的128个代码中的某些总是跟随着第二个字节。这两个字节一起(称作首字节和跟随字节)定义一个字符,通常是一个复杂的象形文字。双字符集问题并不是说字符由两个字节代表。问题在于一些字符(特别是ASCII字符)由1个字节表示。这会引起附加的程序设计问题。例如,字符串中的字符数不能由字符串的字节数决定。必须剖析字符串来决定其长度,而且必须检查每个字节以确定它是否为双字节字符的首字节。如果有一个指向DBCS字符串中间的指针,那么该字符串前一个字符的地址是什么呢?惯用的解决方案是从开始的指针分析该字符串!
  • 与混乱的256个字符代码映像,以及含有一些1字节代码和一些2字节代码的双字节字符集不同,Unicode是统一的16位系统,这样就允许表示65,536个字符。这对表示所有字符及世界上使用象形文字的语言,包括一系列的数学、符号和货币单位符号的集合来说是充裕的。前128个Unicode字符(16位代码从0×0000到0x007F)就是ASCII字符,而接下来的128个Unicode字符(代码从0×0080到0x00FF)是ISO 8859-1对ASCII的扩展。Unicode中不同部分的字符都同样基于现有的标准。这是为了便于转换。希腊字母表使用从0×0370到0x03FF的代码,斯拉夫语使用从0×0400到0x04FF的代码,美国使用从0×0530到0x058F的代码,希伯来语使用从0×0590到0x05FF的代码。中国、日本和韩国的象形文字(总称为CJK)占用了从0×3000到0x9FFF的代码。
  • C语言中, 定义一个双字节的字符 wchar_t c = ‘A’ 或者wchar_t c = L’A', 其中的wchar_t为typedef unsigned short wchar_t ,定义于wchar.h,定义宽字符串的指针 wchar_t *p = L”Hello”
  • 窄字符的函数均有宽字符版本,比如strlen对应wcslen,printf对应wprintf, 在wchar.h和string.h中声明。
  • 维护单一源代码,用VC饱含tchar.h头文件,新的数据类型TCHAR根据是否定义了_UNICODE来确定自身类型为char或者wchar_t,定义字符串时用宏__T或_T或者_TEXT或者__TEXT或者TEXT
  • _UNICODE用于C, UNICODE用于VC
  • 一个Windows程序包括表头文件WINDOWS.H。该文件包括许多其它表头文件,包括WINDEF.H,该文件中有许多在Windows中使用的基本型态定义,而且它本身也包括WINNT.H。WINNT.H处理基本的Unicode支持,WINNT.H的前面包含C的表头文件CTYPE.H,这是C的众多表头文件之一,包括wchar_t的定义。WINNT.H定义了新的数据型态,称作CHAR和WCHAR。
  • typedef char CHAR ;
    typedef wchar_t WCHAR ;    // wc
     
    typedef CHAR * PCHAR, * LPCH, * PCH, * NPSTR, * LPSTR, * PSTR ;
    typedef CONST CHAR * LPCCH, * PCCH, * LPCSTR, * PCSTR ;
    typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;
    typedef CONST WCHAR * LPCWCH, * PCWCH, * LPCWSTR, * PCWSTR ;
     
    #ifdef  UNICODE
    typedef WCHAR TCHAR, * PTCHAR ;
    typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
    typedef LPCWSTR LPCTSTR ;
    #else
    typedef char TCHAR, * PTCHAR ;
    typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
    typedef LPCSTR LPCTSTR ;
    #endif
     
    #define __TEXT(quote) L##quote
    #define TEXT(quote) __TEXT(quote)
    // 还有宏__T或_T或者_TEXT或者__TEXT或者TEXT
  • ASCII宽字符常规
    参数的变数个数
    标准版sprintf
    swprintf
    _stprintf
    最大长度版
    _snprintf
    _snwprintf
    _sntprintf
    Windows版

    wsprintfA
    wsprintfW
    wsprintf
    参数数组的指针

    标准版
    vsprintf
    vswprintf
    _vstprintf
    最大长度版
    _vsnprintf
    _vsnwprintf
    _vsntprintf
    Windows版
    wvsprintfA
    wvsprintfW
    wvsprintf

Posted in API, Windows开发, 代码人生 | Tagged unicide, windows api | Leave a response

Next »

Random Post

  • 香烟后面的女人
  • 思慕的年华
  • 毕业的这几天
  • 如何在WordPress中插入Flash
  • 突然发现

Categories

  • General technic
  • Weblog
  • WordPress
  • 代码人生
    • C++
      • C++知识整理
      • inside VS C++ STL
    • PHP
      • PHP知识整理
      • Zend框架
    • Python
      • Python知识整理
    • Windows开发
      • API
  • 文章发表
  • 纸上挨踢
  • 软件测试
    • 测试工具与技术
    • 测试理论

Archives

Tags

API autodesk auto_ptr C++ GFW hack memory PHP Python SSH stl URL vc windows api Windows开发 Zend框架 代理 函数 女人 字符串 学习 小说 工作 异常 战争 打印 服务 构造函数 模块 樱花 歌曲 武汉大学 泛型编程 爱情 现实 知识整理 类 编码 翻墙 语句 选择 随想 面向对象 面试 香烟 API (4)
C++ (1)
C++知识整理 (17)
General technic (9)
inside VS C++ STL (4)
PHP知识整理 (10)
Python (1)
Python知识整理 (25)
Weblog (23)
Windows开发 (4)
WordPress (1)
Zend框架 (2)
代码人生 (5)
文章发表 (4)
测试工具与技术 (1)
测试理论 (4)
纸上挨踢 (2)

WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.

Bookmarks

  • 张宏良
  • 紫穆兰

Copyright © 2012 Lzp729@Blog.

Powered by WordPress and Hybrid, Theme By Lzp729.

RSS feed Site Map