2011年12月

sqlite3 cmd命令输出乱码

1. 在CMD窗口下输下:chcp 65001 确定

2. 在命令行标题栏上点击右键,选择【属性】 -【字体】,将字体修改为【Lucida Console】 确定

解释一下,因为sqlite3数据存储采用UTF-8。中文windows xp的cmd默认code page是1521

C:\Documents and Settings\Administrator>chcp
Active code page: 1251

通过chcp 65001修改为UTF-8。code page(代码页)是字符集的另外一个术语(term)。

具体各种Code page参考:http://en.wikipedia.org/wiki/Code_page

CEdit子类化限制输入合法QQ号(MFC)

一般CEdit控件默认是可以输入任何的内容,包括数字、字符、符号等。

有时候我们有特殊的需求,限制用户输入合法的QQ号(数字,5<=位数<=10)。

在Dialog的设计器里面右击Edit控件有个Number属性,作用是限制只能输入数字。默认是False,设置为True之后就只能输入数字了。

但是我们还有一个限制位数的需求(5<=位数<=10),这个我们可以通过DDV数据验证机制来完成。在CTestDlg::DoDataExchange()加入:

DDV_MinMaxLongLong(pDX,IDC_QQNUM,10000,9999999999);

当用户输入的范围超出了10000到9999999999这个范围,然后点击确定之后弹出:

CEdit子类化限制输入合法QQ号(MFC)

以上就是不需要子类化就能完成这个需求。我感觉这并不是一个友好的解决方法,如果有比这个更复杂一点的需求,DDV就没什么作用了。

下来来说说子类化的方法是怎么做的。

假设Edit控件ID是IDC_QQNUM

新建一个QQNumEdit类,基类是CEdit。

QQNumEdit.h:

#pragma once
#include "afxwin.h"

class CQQNumEdit :
    public CEdit
{
public:
    CQQNumEdit(void);
    ~CQQNumEdit(void);
protected:
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    DECLARE_MESSAGE_MAP()
};

QQNumEdit.cpp:

#include "stdafx.h"
#include "QQNumEdit.h"

CQQNumEdit::CQQNumEdit()
{

}
CQQNumEdit::~CQQNumEdit()
{

}
BEGIN_MESSAGE_MAP(CQQNumEdit,CEdit)
    ON_WM_CHAR()
END_MESSAGE_MAP()

void CQQNumEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{   
    if(nChar>='0' && nChar<='9' )
    {
        CEdit::OnChar(nChar, nRepCnt, nFlags);
    }
    else
    {
        return;
    }
}

添加了一个OnChar事件。判断输入的范围是否在'0'到'9',不是就直接return返回。

接下来还需要在父对话框中定义一个CQQNumEdit类型的变量:

class CAddUserDlg : public CDialog
{
    //other code.........
public:
    CQQNumEdit m_qqNumEdit;
};

接下来在InitDialog中子类化:

BOOL CAddUserDlg::OnInitDialog()
{
    m_qqNumEdit.SubclassDlgItem(IDC_QQNUM,this);
    //m_qqNumEdit.SetLimitText(10);
    //m_qqNumEdit.UnsubclassWindow();
    return TRUE;
}

子类化使用SubclassDlgItem。不子类化了,使用UnsubclassWindow。设置字符长度SetLimitText,参数就是字符长度。

在这种情况下子类化的方法无需点“确定”,用户输入错误的数据Edit控件是没显示的。感觉要直接一点。

vs2010的mfc项目转vs2005修改的3个地方

首先去掉stdafx.h里面的:

#include <afxcontrolbars.h>     // MFC support for ribbons and control bars

ribbons界面库vs2005版本木有啊。

将CWndEx类都修改为CWnd。vs2005木有CWndEx。

将真彩色的图标换成256色的。

不用AppWizard创建MFC程序

十个月以前写过“不用MFC AppWizard创建MFC项目”,不过是转载别人的,今天自己来写一次。

首先我们用AppWizard创建一个程序mfc1,然后查看mfc1程序属性里面的C/C++命令行和链接器命令行:

C/C++命令行:

/Od /D "WIN32" /D "_WINDOWS" /D "_DEBUG" /D "_AFXDLL" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MDd /Yu"stdafx.h" /Fp"Debugmfc1.pch" /Fo"Debug" /Fd"Debugvc80.pdb" /W3 /nologo /c /Wp64 /ZI /TP /errorReport:prompt 链接器命令行:

/OUT:"d:devDebugmfc1.exe" /INCREMENTAL /NOLOGO /MANIFEST /MANIFESTFILE:"Debugmfc1.exe.intermediate.manifest" /DEBUG /PDB:"d:devdebugmfc1.pdb" /SUBSYSTEM:WINDOWS /ENTRY:"wWinMainCRTStartup" /MACHINE:X86 /ERRORREPORT:PROMPT 接下来我们根据以上命令行来创建一个hardcode程序,添加新项目里面选择“空项目”,然后创建一个头文件hello.h和一个cpp文件hello.cpp(代码来自MFC Windows程序设计(第二版)):

hello.h

class CMyApp : public CWinApp
{
public:
    virtual BOOL InitInstance ();
};

class CMainWindow : public CFrameWnd
{
public:
    CMainWindow ();

protected:
    afx_msg void OnPaint ();
    DECLARE_MESSAGE_MAP ()
};

hello.cpp

#include <afxwin .h>
#include "Hello.h"

CMyApp myApp;

/////////////////////////////////////////////////////////////////////////
// CMyApp member functions

BOOL CMyApp::InitInstance ()
{
    m_pMainWnd = new CMainWindow;
    m_pMainWnd->ShowWindow (m_nCmdShow);
    m_pMainWnd->UpdateWindow ();
    return TRUE;
}

/////////////////////////////////////////////////////////////////////////
// CMainWindow message map and member functions

BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
    ON_WM_PAINT ()
END_MESSAGE_MAP ()

CMainWindow::CMainWindow ()
{
    Create (NULL, _T ("The Hello Application"));
}

void CMainWindow::OnPaint ()
{
    CPaintDC dc (this);
    
    CRect rect;
    GetClientRect (&rect);

    dc.DrawText (_T ("Hello, MFC"), -1, &rect,
        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
}
</afxwin>

以上代码的功能是建立一个最简单的窗口,中心位置用CPaintDC显示一些文字。

点击生成,报错:

d:vs8vcatlmfcincludeafx.h(24) : fatal error C1189: #error : Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d] 提示如果代码生成->运行时库选择了/MD[d]必须定义_AFXDLL,否则不要使用/MD[d]。我们在C/C++->预处理器->预处理器定义加上:WIN32;_WINDOWS;_DEBUG;_AFXDLL;_UNICODE;UNICODE;保持和mfc1程序的一致性。

点击生成,报了另外的错误:

1>正在编译...
1>Hello.cpp
1> WINVER not defined. Defaulting to 0x0502 (Windows Server 2003)
1>正在链接...
1>LINK : 没有找到 d:devDebughardcode.exe 或上一个增量链接没有生成它;正在执行完全链接
1>LINK : fatal error LNK1561: 必须定义入口点

新建一个stdafx.h作预编译头,内容是一些定义版本的信息:

#ifndef WINVER             // 允许使用特定于 Windows XP 或更高版本的功能。
#define WINVER 0x0501       // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT        // 允许使用特定于 Windows XP 或更高版本的功能。
#define _WIN32_WINNT 0x0501 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif                      

#ifndef _WIN32_WINDOWS      // 允许使用特定于 Windows 98 或更高版本的功能。
#define _WIN32_WINDOWS 0x0410 // 将它更改为适合 Windows Me 或更高版本的相应值。
#endif

#ifndef _WIN32_IE           // 允许使用特定于 IE 6.0 或更高版本的功能。
#define _WIN32_IE 0x0600    // 将此值更改为相应的值,以适用于 IE 的其他版本。值。
#endif

然后设置 C/C++ -> 预编译头 -> 创建/使用预编译头 -> 创建预编译头(/Yu)。

在hello.cpp文件中的最顶部加入

#include "stdafx.h"

然后设置 链接器 -> 系统 -> 子系统 -> Windows (/SUBSYSTEM:WINDOWS)

设置 链接器 -> 高级 -> 入口点 -> wWinMainCRTStartup

点击生成,OK了。

不用AppWizard创建MFC程序

(c语言)webqq登录

#define CURL_STATICLIB
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "D:\dev\\yajl\\yajl\\yajl_parse.h"
#include "D:\dev\\yajl\\yajl\\yajl_tree.h"
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"D:\\dev\\curl-7.28.0\\lib\\LIB-Debug\\libcurld.lib")
#pragma comment(lib,"D:\\dev\\Debug\\yajl.lib")

unsigned short chrsz = 8;
char *b64pad = "";
char *validate_code;
unsigned short mode = 32;
unsigned short hexcase = 1;
int hex[16]={0};
typedef struct tagSESSION{
unsigned short retcode,birthday_year,birthday_month,birthday_day,allow,constel,blood,stat,vip_info,shengxiao;
unsigned reg_time;
char occupation[512];
char phone[512];
char college[512];
char homepage[512];
char country[512];
char city[512];
char personal[512];
char nick[512];
char email[512];
char province[512];
char gender[512];
char mobile[512];
__int64 uin;
char vfwebqq[512];
char psessionid[512];
}session;
session sess;

void Ansi2Utf8(char ansibuff[], char utf8buff[])
{
int len = 0;
int wlen = 0;
wchar_t wbuff[1024] = {0};
//ansi->(unicode)->utf8
len = MultiByteToWideChar(CP_ACP,0,ansibuff,-1,NULL,0);
MultiByteToWideChar(CP_ACP,0,ansibuff,-1,wbuff,len);

wlen = wcslen(wbuff);

len = WideCharToMultiByte(CP_UTF8,0,wbuff,wlen,NULL,0,NULL,FALSE);
WideCharToMultiByte (CP_UTF8,0,wbuff,wlen,utf8buff,len,NULL,FALSE);

}

void Utf82Ansi(char utf8buff[], char ansibuff[])
{
int len = 0;
int wlen = 0;
wchar_t wbuff[1024] = {0};
//utf8->(unicode)->ansi
len = MultiByteToWideChar(CP_UTF8,0,utf8buff,-1,NULL,0);
MultiByteToWideChar(CP_UTF8,0,utf8buff,-1,wbuff,len);

wlen = wcslen(wbuff);

len = WideCharToMultiByte(CP_ACP,0,wbuff,-1,NULL,0,NULL,FALSE);
WideCharToMultiByte (CP_ACP,0,wbuff,wlen,ansibuff,len,NULL,FALSE);
}


char *hash2str(unsigned char digest[16])
{
unsigned int i;
char temp[3]={0};
char *hex_str=malloc(16);
memset(hex_str,0,16);
for (i = 0; i < 16; i++)
{
sprintf(temp,"%02X", digest[i]);
strcat(hex_str,temp);
}
return hex_str;
}

unsigned int *str2binl(char *str,size_t str_len)
{
unsigned short b;
unsigned short a = (1<<chrsz)-1;
unsigned int h,i;
unsigned int *bin = (unsigned int*)malloc(200);
memset(bin,0,200);
for(b=0;b<str_len*chrsz;b+=chrsz)
{
h = (((unsigned int)str[b/chrsz]) & a) << (b%32);
i = b>>5;
bin[i] |= h;
}
return bin;
}
char *binl2str(unsigned int *arr)
{
size_t i=0;
char char_temp[2]="";
unsigned short b,a = (1<<8)-1;
char *str=malloc(200);
memset(str,0,200);
while(arr[i] !=0)
{
i++;
}
for(b=0;b<i*32;b+=chrsz)
{
sprintf(char_temp,"%c",(arr[b>>5])>>(b%32)&a );
//char_temp[0] = (char) ;
char_temp[1] = 0;
strcat(str,char_temp);
}
return str;
}
char *binl2hex(unsigned int *arr)
{
size_t j,i=0;
char *str = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
char str_temp[4]="";
char str_temp2[2]="";


char *str_hex=(char*)malloc(100);
memset(str_hex, 0, 100);
while(arr[i] !=0)
{
i++;
}
for(j=0;j<i*4;j++)
{
str_temp[0] = str[arr[j>>2]>>((j%4)*8+4)&0xF];
str_temp[1]=0;
str_temp2[0] = str[arr[j>>2]>>((j%4)*8)&0xF];
str_temp2[1]=0;
strcat(str_temp,str_temp2);
strcat(str_hex,str_temp);
}
return str_hex;
}
unsigned int bit_rol(unsigned int A,unsigned int B)
{
return (A<<B) | (A >>(32-B));
}
unsigned int safe_add(unsigned int A,unsigned int D)
{
unsigned int C = (A & 0xFFFF) + (D &0xFFFF);
unsigned int B = (A >> 16) + (D >> 16) + (C >> 16);
return (B<<16) | (C & 0xFFFF);
}
unsigned int md5_cmn(unsigned int F,unsigned int C, unsigned int B, unsigned int A, unsigned int E, unsigned int D)
{
return safe_add(bit_rol(safe_add(safe_add(C, F), safe_add(A, D)), E), B);
}
unsigned int md5_ff(unsigned int C, unsigned int B, unsigned int G, unsigned int F, unsigned int A, unsigned int E, unsigned int D) {
return md5_cmn((B & G) | ((~B) & F), C, B, A, E, D);
}
unsigned int md5_gg(unsigned int C, unsigned int B, unsigned int G, unsigned int F, unsigned int A, unsigned int E, unsigned int D) {
return md5_cmn((B & F) | (G & (~F)), C, B, A, E, D);
}
unsigned int md5_hh(unsigned int C, unsigned int B, unsigned int G, unsigned int F, unsigned int A, unsigned int E, unsigned int D) {
return md5_cmn(B ^ G ^ F, C, B, A, E, D);
}
unsigned int md5_ii(unsigned int C, unsigned int B, unsigned int G, unsigned int F, unsigned int A, unsigned int E, unsigned int D) {
return md5_cmn(G ^ (B | (~F)), C, B, A, E, D);
}

unsigned int *core_md5(unsigned int *K, unsigned int F)
{
unsigned int len,i;
unsigned int C;
unsigned int E,D,B,A;
unsigned int J = 1732584193;
unsigned int I = -271733879;
unsigned int H = -1732584194;
unsigned int G = 271733878;

K[F >> 5] |= 128 << ((F) % 32);
len =(((F + 64) >> 9) << 4) + 14;
K[len] = F;

for (C = 0; C < len+1; C += 16) {
E = J;
D = I;
B = H;
A = G;
J = md5_ff(J, I, H, G, K[C + 0], 7, -680876936);
G = md5_ff(G, J, I, H, K[C + 1], 12, -389564586);
H = md5_ff(H, G, J, I, K[C + 2], 17, 606105819);
I = md5_ff(I, H, G, J, K[C + 3], 22, -1044525330);
J = md5_ff(J, I, H, G, K[C + 4], 7, -176418897);
G = md5_ff(G, J, I, H, K[C + 5], 12, 1200080426);
H = md5_ff(H, G, J, I, K[C + 6], 17, -1473231341);
I = md5_ff(I, H, G, J, K[C + 7], 22, -45705983);
J = md5_ff(J, I, H, G, K[C + 8], 7, 1770035416);
G = md5_ff(G, J, I, H, K[C + 9], 12, -1958414417);
H = md5_ff(H, G, J, I, K[C + 10], 17, -42063);
I = md5_ff(I, H, G, J, K[C + 11], 22, -1990404162);
J = md5_ff(J, I, H, G, K[C + 12], 7, 1804603682);
G = md5_ff(G, J, I, H, K[C + 13], 12, -40341101);
H = md5_ff(H, G, J, I, K[C + 14], 17, -1502002290);
I = md5_ff(I, H, G, J, K[C + 15], 22, 1236535329);
J = md5_gg(J, I, H, G, K[C + 1], 5, -165796510);
G = md5_gg(G, J, I, H, K[C + 6], 9, -1069501632);
H = md5_gg(H, G, J, I, K[C + 11], 14, 643717713);
I = md5_gg(I, H, G, J, K[C + 0], 20, -373897302);
J = md5_gg(J, I, H, G, K[C + 5], 5, -701558691);
G = md5_gg(G, J, I, H, K[C + 10], 9, 38016083);
H = md5_gg(H, G, J, I, K[C + 15], 14, -660478335);
I = md5_gg(I, H, G, J, K[C + 4], 20, -405537848);
J = md5_gg(J, I, H, G, K[C + 9], 5, 568446438);
G = md5_gg(G, J, I, H, K[C + 14], 9, -1019803690);
H = md5_gg(H, G, J, I, K[C + 3], 14, -187363961);
I = md5_gg(I, H, G, J, K[C + 8], 20, 1163531501);
J = md5_gg(J, I, H, G, K[C + 13], 5, -1444681467);
G = md5_gg(G, J, I, H, K[C + 2], 9, -51403784);
H = md5_gg(H, G, J, I, K[C + 7], 14, 1735328473);
I = md5_gg(I, H, G, J, K[C + 12], 20, -1926607734);
J = md5_hh(J, I, H, G, K[C + 5], 4, -378558);
G = md5_hh(G, J, I, H, K[C + 8], 11, -2022574463);
H = md5_hh(H, G, J, I, K[C + 11], 16, 1839030562);
I = md5_hh(I, H, G, J, K[C + 14], 23, -35309556);
J = md5_hh(J, I, H, G, K[C + 1], 4, -1530992060);
G = md5_hh(G, J, I, H, K[C + 4], 11, 1272893353);
H = md5_hh(H, G, J, I, K[C + 7], 16, -155497632);
I = md5_hh(I, H, G, J, K[C + 10], 23, -1094730640);
J = md5_hh(J, I, H, G, K[C + 13], 4, 681279174);
G = md5_hh(G, J, I, H, K[C + 0], 11, -358537222);
H = md5_hh(H, G, J, I, K[C + 3], 16, -722521979);
I = md5_hh(I, H, G, J, K[C + 6], 23, 76029189);
J = md5_hh(J, I, H, G, K[C + 9], 4, -640364487);
G = md5_hh(G, J, I, H, K[C + 12], 11, -421815835);
H = md5_hh(H, G, J, I, K[C + 15], 16, 530742520);
I = md5_hh(I, H, G, J, K[C + 2], 23, -995338651);
J = md5_ii(J, I, H, G, K[C + 0], 6, -198630844);
G = md5_ii(G, J, I, H, K[C + 7], 10, 1126891415);
H = md5_ii(H, G, J, I, K[C + 14], 15, -1416354905);
I = md5_ii(I, H, G, J, K[C + 5], 21, -57434055);
J = md5_ii(J, I, H, G, K[C + 12], 6, 1700485571);
G = md5_ii(G, J, I, H, K[C + 3], 10, -1894986606);
H = md5_ii(H, G, J, I, K[C + 10], 15, -1051523);
I = md5_ii(I, H, G, J, K[C + 1], 21, -2054922799);
J = md5_ii(J, I, H, G, K[C + 8], 6, 1873313359);
G = md5_ii(G, J, I, H, K[C + 15], 10, -30611744);
H = md5_ii(H, G, J, I, K[C + 6], 15, -1560198380);
I = md5_ii(I, H, G, J, K[C + 13], 21, 1309151649);
J = md5_ii(J, I, H, G, K[C + 4], 6, -145523070);
G = md5_ii(G, J, I, H, K[C + 11], 10, -1120210379);
H = md5_ii(H, G, J, I, K[C + 2], 15, 718787259);
I = md5_ii(I, H, G, J, K[C + 9], 21, -343485551);
J = safe_add(J, E);
I = safe_add(I, D);
H = safe_add(H, B);
G = safe_add(G, A);
}
for(i=0;i<16;i++)
{
hex[i]=0;
}
if (mode == 16) {
hex[0]=I;
hex[1]=H;
} else {
hex[0]=J;
hex[1]=I;
hex[2]=H;
hex[3]=G;
}
return hex;
}
char *hex_md5(char *A, int len) {
return binl2hex(core_md5(str2binl(A,len),len*8));
}
char *md5(char *A, int len) {
return hex_md5(A,len);
}

char *md5_3(char *b)
{
unsigned int *a = (unsigned int *)malloc(16);
size_t len = strlen(b);
memset(a,0,16);
a = core_md5(str2binl(b,strlen(b)),(unsigned int)len * chrsz);
a = core_md5(a,16*chrsz);
a = core_md5(a,16*chrsz);
return binl2hex(a);
}
size_t vacode_check( void *ptr, size_t size, size_t nmemb, void *stream)
{
if(strchr(ptr,'!') == NULL)
{
//printf("not what we want:%s\n",ptr);
validate_code=ptr;
return 0;
}
else
{
validate_code=strchr(ptr,'!');
validate_code[4]=0;
return 1;
}
}
size_t fake_write( char *ptr, size_t size, size_t nmemb, char *stream)
{
strcat(stream,ptr);
return(nmemb*size);

}
static void print_cookies(CURL *curl)
{
CURLcode res;
struct curl_slist *cookies;
struct curl_slist *nc;
int i;

printf("Cookies, curl knows:\n");
res = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
if (res != CURLE_OK) {
fprintf(stderr, "Curl curl_easy_getinfo failed: %s\n", curl_easy_strerror(res));
exit(1);
}
nc = cookies, i = 1;
while (nc) {
printf("[%d]: %s\n", i, nc->data);
nc = nc->next;
i++;
}
if (i == 1) {
printf("(none)\n");
}
curl_slist_free_all(cookies);
}
DWORD WebQQ_getimage(char* QQno)
{
BYTE buffer[4096] = {0};
char get_url[100] = {0};
char szPath[MAX_PATH] = {0};
char szFile[MAX_PATH] = {0};
char temp[2] = {0};
CURL *easy_handle;
HANDLE hFile = INVALID_HANDLE_VALUE;
easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return CURLE_FAILED_INIT;
}
sprintf(get_url,"http://captcha.qq.com/getimage?aid=2001601&r=0.46165929990820587&uin=%s",QQno);
curl_easy_setopt(easy_handle, CURLOPT_URL, get_url);
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20121029001");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA,buffer);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR, "D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);

GetModuleFileName(NULL, szPath, MAX_PATH);
strcpy(szFile, szPath);
strcat(szFile, "getimage.png");
hFile = CreateFile(szFile, )



}
DWORD WebQQ_check(char* QQno, char* validateCode, char* qqHex)
{
char buffer[100] = {0};
char get_url[100] = {0};
char temp[2] = {0};
CURL *easy_handle;
easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return CURLE_FAILED_INIT;
}
sprintf(get_url,"http://check.ptlogin2.qq.com/check?uin=%s&appid=1003903",QQno);
curl_easy_setopt(easy_handle, CURLOPT_URL, get_url);
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%%3A%%2F%%2Fweb.qq.com%%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120920001");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA,buffer);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR, "D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);

sscanf(buffer,"ptui_checkVC('0','%[^']','%[^']')", validateCode, qqHex);

return 0;

//返还 QQ验证码 和 QQ号的hex字符串
/*
if(strchr(buffer,'!') == NULL)
{
return NULL;
}
else
{
buffer=strchr(buffer,'!');
buffer[4]=0;
return buffer;
}
*/

}
void WebQQ_login(char* QQno,char* PassCode,char* VeriCode,char* szLoginResult)
{
char buffer[1024] = {0};
char get_url[1024] = {0};

CURL *easy_handle = curl_easy_init();
memset(buffer,0,100);
memset(get_url,0,500);
sprintf(get_url,"http://ptlogin2.qq.com/login?u=%s&p=%s&verifycode=%s&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%%3A%%2F%%2Fweb.qq.com%%2Floginproxy.html%%3Flogin2qq%%3D1%%26webqq_type%%3D10&h=1&ptredirect=0&ptlang=2052&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=2-16-18434&mibao_css=m_webqq&t=1&g=1",QQno,PassCode,VeriCode);

curl_easy_setopt(easy_handle, CURLOPT_URL, get_url);
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://ui.ptlogin2.qq.com/cgi-bin/login?target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%%3A%%2F%%2Fweb.qq.com%%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20120920001");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, szLoginResult);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,"D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);

}

void get_json_string(char buffer[],char errbuf[],char** path, char* outBuf)
{
yajl_val v;
yajl_val node;
char utf8buff[1024] = {0};

//Ansi2Utf8(buffer, utf8buff);

node = yajl_tree_parse(buffer, errbuf, 2000);

v = yajl_tree_get(node, path, yajl_t_string);
strcpy(utf8buff, YAJL_GET_STRING(v));
Utf82Ansi(utf8buff, outBuf);
yajl_tree_free(v);
}
void get_json_number(char buffer[],char errbuf[],char** path, __int64* dwNum)
{
yajl_val v;
yajl_val node;
char utf8buff[1024] = {0};

//Ansi2Utf8(buffer, utf8buff);

node = yajl_tree_parse(buffer, errbuf, 2000);

v = yajl_tree_get(node, path, yajl_t_number);
*dwNum = YAJL_GET_INTEGER(v);

yajl_tree_free(v);
}

void WebQQ_login2()
{
char* path[20] = { "result", "vfwebqq", (char *) 0 };
char cookieBuf[2000] = {0};
char ptwebqqBuf[65] = {0};
char* p_ptwebqq = NULL;
char buffer[1000] = {0};
char errbuffer[2000] = {0};
char szClient[20] = {0};
char post_data[500] = {0};
int iRet = 0;

CURL *easy_handle;
FILE* fp = fopen("D:\\cookie_login.txt","r");
strcpy(szClient, "7823373");

fread(cookieBuf,2000,1,fp);
p_ptwebqq = strstr(cookieBuf,"ptwebqq\t") + strlen("ptwebqq\t");
memcpy(ptwebqqBuf, p_ptwebqq, 64);
ptwebqqBuf[64] = '\0';

if(fp != NULL)
fclose(fp);

easy_handle = curl_easy_init();
sprintf(post_data,"r={\"status\":\"online\",\"ptwebqq\":\"%s\",\"passwd_sig\":\"\",\"clientid\":\"%s\",\"psessionid\":null}&clientid=%s&psessionid=null",ptwebqqBuf,szClient,szClient);
curl_easy_setopt(easy_handle, CURLOPT_URL, "http://d.web2.qq.com/channel/login2");
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=3");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS,post_data);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,"D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);

get_json_string(buffer,errbuffer,path, sess.vfwebqq);
path[1] = "psessionid";
get_json_string(buffer,errbuffer,path, sess.psessionid);
printf("登录成功\n");
}
void WebQQ_get_friend_info2(char* qq_id)
{
CURL *easy_handle = NULL;
char url[300] = {0};
char buffer[2000] = {0};
WCHAR wbuffer[2000] = {0};
char errbuf[2000] = {0};
char* path[20] = { "result", "uin", (char *) 0 };


sprintf(url,"http://s.web2.qq.com/api/get_friend_info2?tuin=%s&verifysession=&code=&vfwebqq=%s&t=1349263842810",qq_id,sess.vfwebqq);
easy_handle = curl_easy_init();
curl_easy_setopt(easy_handle, CURLOPT_URL, url);
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://s.web2.qq.com/proxy.html?v=20110412001&callback=1&id=1");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,"D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);


get_json_number(buffer,errbuf,path, &sess.uin);
path[1] = "country"; //debug fail...........
get_json_string(buffer,errbuf,path, sess.country);
path[1] = "homepage";
get_json_string(buffer,errbuf,path, sess.homepage);
path[1] = "nick";
get_json_string(buffer,errbuf,path, sess.nick);
path[1] = "gender";
get_json_string(buffer,errbuf,path, sess.gender);
printf("QQ号:%I64d|昵称:%s|国家:%s|主页:%s|性别:%s\n",sess.uin,sess.nick,sess.country,sess.homepage,sess.gender);

}
void WebQQ_get_user_friends2()
{
CURL *easy_handle;
char post_fields[200] = {0};
char buffer[10000] = {0};
char errbuf[2000] = {0};
WCHAR wbuffer[10000] = {0};
char* path[20] = { "result", "info", (char *) 0 };

easy_handle = curl_easy_init();
curl_easy_setopt(easy_handle, CURLOPT_URL, "http://s.web2.qq.com/api/get_user_friends2");
curl_easy_setopt(easy_handle, CURLOPT_REFERER, "http://s.web2.qq.com/proxy.html?v=20110412001&callback=1&id=2");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
curl_easy_setopt(easy_handle, CURLOPT_POST,1);
sprintf(post_fields,"{\"h\":\"hello\",\"vfwebqq\":\"%s\"}",sess.vfwebqq);
curl_easy_setopt(easy_handle, CURLOPT_POSTFIELDS,post_fields);
curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA, buffer);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR,"D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
curl_easy_cleanup(easy_handle);

printf("在线好友:???\n");

}
void testaccess()
{

//curl_easy_setopt(easy_handle, CURLOPT_URL, "http://b.qzone.qq.com/cgi-bin/blognew/blog_output_titlelist?uin=2508491710&vuin=0&property=GoRE&getall=1&imgdm=imgcache.qq.com&bdm=b.qzone.qq.com&category=&numperpage=40&sorttype=0&arch=0&pos=0&direct=1");


char buffer[10000]={0};
CURL *easy_handle;
easy_handle = curl_easy_init();
if (NULL == easy_handle)
{
curl_global_cleanup();
return;
}
//sprintf(get_url,"http://www.google.com.hk",QQno);
curl_easy_setopt(easy_handle, CURLOPT_URL, "http://b.qzone.qq.com/cgi-bin/blognew/blog_output_titlelist?uin=2508491710&vuin=0&property=GoRE&getall=1&imgdm=imgcache.qq.com&bdm=b.qzone.qq.com&category=&numperpage=40&sorttype=0&arch=0&pos=0&direct=1");
curl_easy_setopt(easy_handle, CURLOPT_VERBOSE,1);
//curl_easy_setopt(easy_handle, CURLOPT_WRITEFUNCTION, fake_write);
//curl_easy_setopt(easy_handle, CURLOPT_WRITEDATA,buffer);
curl_easy_setopt(easy_handle, CURLOPT_COOKIEFILE,"D:\\cookie_login.txt");
curl_easy_setopt(easy_handle, CURLOPT_COOKIEJAR, "D:\\cookie_login.txt");
curl_easy_perform(easy_handle);
printf("%s",buffer);
curl_easy_cleanup(easy_handle);

}
//16进制的字符串转为数字 比如:"E"->E(Hex)->14(Oct)
void hexchar2bin(char str[], unsigned char k[])
{
size_t i = 0;
size_t j = 0;
size_t len = 0;
unsigned short m,n = 0;
len = strlen(str);
for(i = 0 ; i<len; i+=2){
if(str[i] >=65)//如果大写字母字符
{
m = str[i] - 55;
}
else//如果是数字
{
m = str[i] - 48;
}

if(str[i+1] >=65)//如果大写字母字符
{
n = str[i+1] - 55;
}
else//如果是数字
{
n = str[i+1] - 48;
}

k[j] = m*16 + n;

j++;

}
}
void JsNotation2Str(char *qqHex, unsigned char *chrqqHex)
{
unsigned short i=0;
unsigned short j=0;
unsigned short m=0;
unsigned short n=0;
unsigned short len=0;
len = strlen(qqHex);
for(i=0; i<len; i+=4)
{
/*
if(qqHex[i+2] == '0' && qqHex[i+3] == '0')
continue;
*/
if(qqHex[i+2] >= 97)//小写字幕
{
m = qqHex[i+2] - 87;
}
else if(qqHex[i+2] >=65)//如果大写字母字符
{
m = qqHex[i+2] - 55;
}
else//如果是数字
{
m = qqHex[i+2] - 48;
}

if(qqHex[i+3] >= 97)//小写字幕
{
n = qqHex[i+3] - 87;
}
else if(qqHex[i+3] >=65)//如果大写字母字符
{
n = qqHex[i+3] - 55;
}
else//如果是数字
{
n = qqHex[i+3] - 48;
}

chrqqHex[j] = m*16 + n;
j++;

}
}

void main()
{
int nRet = 0;
int i = 0;
int len = 0;
char *qq_id = "2508491710",*qq_pass="password";
char passcode[128] = {0};
char passcodeTemp[128] = {0};
char login_result[1024] = {0};
unsigned char bin[33] = {0};
char validateCode[100] = {0};
char qqHex[100] = {0};
char chrqqHex[9] = {0};


nRet = WebQQ_check(qq_id, validateCode, qqHex);

//encrypt
//加密方式改变了
//md5( md5(hexchar2bin(md5("password")) + "\x00\x00\x00\x00\x95\x84\x8B\xBE") + "!YRB" )
//"\x00\x00\x00\x00\x95\x84\x8B\xBE"的QQ好转为16进制再转为字符串

//qqHex转为unsigned char

JsNotation2Str(qqHex, chrqqHex);


hexchar2bin(md5(qq_pass,strlen(qq_pass)), bin);

strcpy(passcodeTemp, bin);
//strcat(passcodeTemp, chrqqHex);
//将8Byte长chrqqHex附加到passcodeTemp中
len = strlen(passcodeTemp);
for(i=0;i<8;i++)
{
passcodeTemp[len + i] = chrqqHex[i];
}


strcpy(passcode, md5(passcodeTemp,16+8));

strcpy(passcodeTemp, passcode);
strcat(passcodeTemp, validateCode);

strcpy(passcode, md5(passcodeTemp,32+4));


//login
WebQQ_login(qq_id,passcode,validateCode, login_result);

//login2
WebQQ_login2();
WebQQ_get_friend_info2(qq_id);
WebQQ_get_user_friends2();

//testaccess();

getchar();
}

用libcurl做http request。

用yajl解析json。

哥将md5算法的javascript实现转为了C语言。转换中发现了一些有趣的东西:>>>(无符号的右移运算符,JS特有,C没有这个运算符,但是C可以通过>>的逻辑右移来实现此运算)

WebQQ的登录过程分一下几个步骤,网上已经有详细的讲解,我就不详讲了。

  1. 取得验证码check,如果是以!开头的四位字符就无需输入验证码,当然console下面无法显示验证码。
  2. 本地md5_3加密完之后login。
  3. cookie中取得ptwebqq之后以json格式login2发送数据。
  4. login2返回json格式的vfwebqq和psessionid。保存起来。
  5. 登录后的每次操作(包括重新登录)都需要vfwebqq和psessionid作为token发送。

后续的获取好友列表,接受、发送消息没做。都是用json做交互。哥发现了yajl一处不好用的地方[1,2]就没有继续写下去了。暂时到这里吧。