档案

Archive for the ‘Visual Studio Development’ Category

vs2010编译MySQL 5.5.15并生成安装包

2011/08/19 留下评论

1.准备:
a. 下载mysql-5.5.15.zip http://dev.mysql.com/downloads/mysql/
b. 下载较新版本的CMake并安装,我使用的是CMake 2.85
c. 下载bison并安装,注意安装目录不能有空格.http://gnuwin32.sourceforge.net/packages/bison.htm
2. 解压mysql-5.5.15.zip,修改sql\sql_locale.cc,因该文件中有很多vs2010不能识别的多国语言的字符编码,实验发现及时改变成任何utf8类型的编码格式仍不行,后发现vs2010有对UTF8兼容的bug,故只好修改该文件,让它暂时只支持en_US一种语言。
3.将bison安装目录中bin\m4.exe拷贝到mysql-5.5.15\sql目录,使其与sql_yacc.cc在同一个目录下,此问题为bison调用m4.exe时无法找到其路径,应该是cmakelist.txt的问题。期间可能还会发生m4.exe找不到GNUWin32包的动态库的问题,去GNUWin32找相应的库下载并拷贝到mysql-5.5.15\sql下。
4.cmake gui 下配置生成工程文件MySQL.sln.
5.控制台下进到MySQL.sln所在目录执行:

"c:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" MySQL.sln /build RelWithDebInfo
"c:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" MySQL.sln /build RelWithDebInfo /project initial_database
"c:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" MySQL.sln /build RelWithDebInfo /project PACKAGE
"c:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe" MySQL.sln /clean

至此如果没有异议会在MySQL.sln所在目录会找到_CPack_Packages\win32\ZIP,会有一个mysql-5.5.15-win32.zip和完整的安装包mysql-5.5.15-win32,这就是最终生成的可以使用的安装包了。

********************************************************************

updated for mysql-5.5.16:

同样是m4.exe生成sql_yacc.cc的问题,在此版本中,需要copy m4.exe及其依赖的动态库与MySQL.sln保持在同一个目录下。–2011-09-22

关于封装文件内存映射

2011/07/03 留下评论

1. c++/MFC 封装好的文件内存映射类 摘自http://hi.baidu.com/andywangcn/blog/item/90c16635e32b70bbd1a2d359.html

首先介绍内存映射文件操作——函数的用法以及先后执行顺序

// 第一步:创建文件
HANDLE hFile = CreateFileForMapping(_T(“MyMemFile.dat”), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
ASSERT(hFile != 0);

// 第二步:创建内存映射文件对象
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024,
_T(“MyMapppingFile”));
ASSERT(hMapFile != 0);

// 第三步:获取内存映射文件对象视图
BYTE* pData = (BYTE*)MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 1024);
ASSERT(pData != NULL);

// 对 pData 指针进行读写操作
// ……

// 第四步:取消内存视图映射
UnmapViewOfFile(pData);

// 第五步:关闭内存映射对象句柄
CloseHandle(hMapFile);

// 第六步:关闭文件句柄
CloseHandle(hFile);

=================================header file=========================================

// MapFile.h : header file
#if !defined(AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_)
#define AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/////////////////////////////////////////////////////////////////////////////
// CMapFile class 使用说明:
// 1 一个对象,打开文件映射之后,立即处理,处理完之后才能再用它打开另一个文件映射

class CMapFile
{
public:
CMapFile();           // protected constructor used by dynamic creation
virtual ~CMapFile();
// Attributes
public:
PVOID m_pvFile;
BOOL m_bSmooth; // 为TRUE表示不阻塞,即不弹出任何对话框
private:
HANDLE hFileMap;

// Operations
public:
BOOL OpenMapFile(CString sFile);

// Implementation
public:
BOOL CloseMapFile();

};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MAPFILE_H__D067E5C8_C4D7_4569_A6BB_9D651FB3F396__INCLUDED_)

=========================================implementation file===========================

// MapFile.cpp : implementation file
#include “stdafx.h”
#include “MapFile.h”

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMapFile

CMapFile::CMapFile()
{
m_pvFile=NULL;
m_bSmooth=FALSE;
}

CMapFile::~CMapFile()
{
if(NULL!=m_pvFile)
{
UnmapViewOfFile(m_pvFile);
m_pvFile=NULL;
}
}

/////////////////////////////////////////////////////////////////////////////
// CMapFile operation handlers
// 空文件会弹出 map could not be opened,在里面敲一个回车,就好了
BOOL CMapFile::OpenMapFile(CString sFile)
{
if(NULL!=m_pvFile)
{
UnmapViewOfFile(m_pvFile);//在当前应用程序的内存地址空间解除对一个文件映射对象的映射
m_pvFile=NULL;
}

// 1:创建或打开一个文件内核对象: Open the file for reading and writing.
// 这里CreateFile函数的参数,路径无论是否有空格都不能有引号,有引号的时候会出错。
HANDLE hFile = CreateFile(sFile,GENERIC_READ|GENERIC_WRITE,
0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

// 由于hFile即使为INVALID_HANDLE_VALUE,下面的CreateFileMapping仍然可以正常运行,
// 所以这里一定要对hFile进行检查!
if (hFile == INVALID_HANDLE_VALUE)
{
if(!m_bSmooth) // 为TRUE表示不阻塞,即不弹出任何对话框
{
AfxMessageBox(_T(“File[“)+sFile+_T(“]could not be opened. Maybe it’s not exist.”));
}
return FALSE;
}

// 2:创建一个文件映射内核对象

DWORD dwFileSize = GetFileSize(hFile, NULL);
//获取文件大小=文件长度+(WCHAR)”(ssume the whole file can be mapped)

// Create the file-mapping object. The file-mapping object is 1 character
// bigger than the file size so that a zero character can be placed at the
// end of the file to terminate the string (file). Because I don’t yet know
// if the file contains ANSI or Unicode characters, I assume worst case
// and add the size of a WCHAR instead of CHAR.

hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0,
dwFileSize+1, /*sizeof(WCHAR)==2,sizeof(char)==1*/
//因为我们要在文件的末尾加上一个字符串的结束符”, 当我们将这个文件映射到内存中时,
//我们就可以像操作字符串一样地来操作文件了。
//如果该文件小于设定的大小,本函数将扩展该文件的大小,使磁盘上的文件变大。这样当以后将该文件作为内存映射 文件使用时,物理存储器就已经存在了。
NULL         // 这个文件映射对象的名字用于与其他进程共享该对象,这里我们还用不到。
);

if (hFileMap == NULL)
{
if(!m_bSmooth)
{
AfxMessageBox(_T(“File[“)+sFile+_T(“] map could not be opened. May be it’s empty.”));
}
return FALSE;
}

// 3:将文件数据映射到进程的地址空间:
// 当创建了一个文件映射对象之后,仍然必须让系统为文件的数据保留一个地址空间区域,
// 并将文件的数据作为映射到该区域的物理存储器进行提交。

m_pvFile = MapViewOfFile(hFileMap,/*FILE_MAP_WRITE*/FILE_MAP_READ,0,0,0);//获取映射文件在内存中的首地址

//CloseHandle(hFileMap);// 关闭内存映射对象句柄
if (m_pvFile == NULL)
{
if(!m_bSmooth)
{
AfxMessageBox(_T(“Could not map view of file[“)+sFile+_T(“].”));
}
return FALSE;
}

// 4:既然我们通过pvFile得到了映象视图的起始地址,那么可以对视图做一些操作了:

// ANSI版本:
// PSTR pchANSI = (PSTR) m_pvFile;
// UNICODE版本:
// PWSTR pchUnicode = (PWSTR) pvFile;如char* sz=(char*)m_pvFile;sz[dwFileSize/sizeof(char)]=”;

// 5:从进程的地址空间中撤销文件数据的映象:
// UnmapViewOfFile(m_pvFile); // 封装为类,映象要在其他地方使用所以这句话要去掉

// 6:关闭文件映射对象和文件对象:
// CloseHandle(hFileMap);
//我们改变了文件的长度,因此要重新设置文件的结束符以删除留在文件尾部的多余内容(比如删除我们先前加到文件末尾的”字符)
SetFilePointer(hFile,dwFileSize, NULL, FILE_BEGIN);
SetEndOfFile(hFile); //设定当前文件指针所在处为文件结束处.该处后面的内容将被删除
CloseHandle(hFile);
return TRUE;
}

BOOL CMapFile::CloseMapFile()
{
if(NULL!=m_pvFile)
{
//取消内存视图映射
if(UnmapViewOfFile(m_pvFile))
{
m_pvFile=NULL;
CloseHandle(hFileMap);// 关闭内存映射对象句柄
return TRUE;
}
return FALSE;
}
return TRUE;
}

2. ShareMem

#include <afxmt.h>
struct RWStr
{
	int readIndex;
	int writeIndex;
};

class AFX_EXT_CLASS ShareMem
{

public:
	ShareMem(int bufNum, int bufSize, char* bufName,int* isSuc);  //构造函数
	~ShareMem();

public:
	BOOL Read(LPVOID data); 				//读数据
	BOOL Write(LPVOID data);				//写数据
	BOOL Release();
private:
	char* name;
	char* indexName;
	int  size;
	int  num;

	struct RWStr rw; 

	CSemaphore* writeSemap;
	CSemaphore*	readSemap;

	CMutex*   rMutex;
	CMutex*   wMutex;
	CMutex*   pMutex;
	HANDLE		buffer;
	HANDLE		pointer;
	LPVOID		pBegin;
	LPVOID		pIndex;

};
#include "stdafx.h"
#include <iostream>
#include <string>
#include "ShareMem.h"

using namespace std;

/*
int bufNum			//要申请缓存的数目
int bufSize			//每个缓存的大小,在写入和读取数据时,以bufSize为单位
char* bufName		//缓存的名称,每个缓存必须有唯一的名称
int* isSuc			//输出参数,构造成功(*isSuc)为0,失败则为-1
*/
ShareMem::ShareMem(int bufNum, int bufSize, char* bufName,int* isSuc)
{
	*isSuc=0;

	if(num<1024*100)
		num=1024*100;
	else
		num=bufNum;

	size=bufSize;
	name=bufName;

	char temp[100];
	strcpy(temp,name);
	strcat(temp,"pointer");

	indexName=temp;
	//cout<<indexName<<endl;

//步骤一:调用CreateFile()函数,以适当的方式创建或打开一个文件核心对象;
//步骤二:把CreateFile()函数返回的文件句柄作为参数,传给CreateFileMapping()函数,
//	由 CreateFileMapping()函数创建一个文件映射核心对象的适当属性;
	pointer=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(rw),indexName);

	if(pointer==NULL)
	{
		*isSuc=-1;
		return;
	}

//步骤三:创建了文件映射核心对象后,调用MapViewOfFile()函数,告诉系统把文件的哪一部分映射到进程的地址空间中,以何种方式映射;
	if(!(GetLastError()==ERROR_ALREADY_EXISTS))
	{
		pIndex=MapViewOfFile(pointer, FILE_MAP_WRITE,0,0,0);
		ZeroMemory(pIndex,sizeof(rw));
	}
	else
		pIndex=MapViewOfFile(pointer, FILE_MAP_WRITE,0,0,0);

	memcpy((void*)&rw,pIndex,sizeof(rw));

	//read互斥体
	char* tempName=NULL;
	strcpy(temp,name);
	strcat(temp,"rMutex");
	tempName=temp;
	rMutex=new CMutex(FALSE,tempName);

	//writ互斥体
	strcpy(temp,name);
	strcat(temp,"wMutex");
	tempName=temp;
	wMutex=new CMutex(FALSE,tempName);

	//
	strcpy(temp,name);
	strcat(temp,"pMutex");
	tempName=temp;
	pMutex=new CMutex(FALSE,tempName);

	//writ信号量
	strcpy(temp,name);
	strcat(temp,"write");
	tempName=temp;
	writeSemap=new CSemaphore(num,num,tempName);

	//read信号量
	strcpy(temp,name);
	strcat(temp,"read");
	tempName=temp;
	readSemap=new CSemaphore(0,num,tempName);

	if(rMutex==NULL||wMutex==NULL||pMutex==NULL||writeSemap==NULL||readSemap==NULL)
	{
		*isSuc=-1;
		return;
	}

	buffer = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,num*size,name);
	if(buffer==NULL)
	{
		*isSuc=-1;
		//cout<<"Create Mapping Faile!"<<endl;
		return;
	}

//步骤四:利用MapViewOfFile()函数返回的指针来使用文件数据;
	pBegin=MapViewOfFile(buffer, FILE_MAP_WRITE,0,0,0);
}

ShareMem::~ShareMem()
{
//步骤五:操作完毕后,调用UnmapViewOfFile()函数,告诉系统 撤销对文件映射核心对象的映射;
	BOOL unBuffer = UnmapViewOfFile( pBegin );
	BOOL unIndex = UnmapViewOfFile( pIndex );
	if(!(unIndex && unBuffer))
	{
		//cout<<"Unmap Faile!"<<endl;
	}
}

/*
功能说明:释放资源

返回值:
操作成功则返回TRUE
操作失败返回FALSE
*/
BOOL ShareMem::Release()
{
	HANDLE temp1 = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,num*size,name);
	HANDLE temp2 = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(rw),indexName);

	if(temp1!=NULL&&temp2!=NULL)
	{
//步骤六:使用CloseHandle()函数关闭文件映射核心对象;
//步骤七:使用CloseHandle()函数关闭文件核心对象;
		CloseHandle(temp1);
		CloseHandle(temp2);
	}
	else
		return FALSE;

	if(rMutex!=NULL&&wMutex!=NULL&&writeSemap!=NULL&&readSemap!=NULL)
	{
		delete rMutex;
		delete wMutex;
		delete writeSemap;
		delete readSemap;
	}

	return TRUE;
}

/*
功能说明:从缓存读取数据,以bufSize为单位

参数说明:
LPVOID data	//所要得到数据的指针,读取具体数据结构时可先进行强制转换后再传入参数

返回值:
操作成功则返回TRUE,data保存所读取的数据
操作失败返回FALSE,data无定义
*/
BOOL ShareMem::Read(LPVOID data)
{
	readSemap->Lock();
	pMutex->Lock();

	memcpy((void*)&rw,pIndex,sizeof(rw));

	LPVOID read=(LPVOID)((char*)pBegin+rw.readIndex*size);
	memcpy(data,read,size);
	//cout<<"Geted id: "<<*(int*)data<<"  Read index:"<<rw.readIndex<<endl;

	rMutex->Lock();
	rw.readIndex=(rw.readIndex+1)%num;
	rMutex->Unlock();

	memcpy(pIndex,(void*)&rw,sizeof(rw));

	pMutex->Unlock();
	writeSemap->Unlock();		

	if(read==NULL)
	{
		//cout<<"Failed to Map(read): "<<GetLastError()<<endl;
		return FALSE;
	}
	return TRUE;
}

/*
功能说明:向缓存写入数据,以bufSize为单位

参数说明:
LPVOID data	//所要写入数据的指针,写入具体数据结构时可先进行强制转换后再传入参数

返回值:
操作成功则返回TRUE,data为写入的数据
操作失败返回FALSE,data无定义
*/
BOOL ShareMem::Write(LPVOID data)
{
	writeSemap->Lock();
	pMutex->Lock();

	memcpy((void*)&rw,pIndex,sizeof(rw));	

	LPVOID write=(LPVOID)((char*)pBegin+rw.writeIndex*size);
	memcpy(write,data,size);
	//cout<<"Thread id:"<<GetCurrentThreadId()<<"  Write index:"<<rw.writeIndex<<endl;

	wMutex->Lock();
	rw.writeIndex=(rw.writeIndex+1)%num;
	wMutex->Unlock();

	memcpy(pIndex,(void*)&rw,sizeof(rw));
	pMutex->Unlock();

	readSemap->Unlock();

	if(write==NULL)
	{
		//cout<<"Failed to Map(write): "<<GetLastError()<<endl;
		return FALSE;
	}
	return TRUE;
}
3.CMemMapFile 1.53 http://www.naughter.com/memmap.html
4.Shared Memory--win32 programming http://comsci.liu.edu/~murali/win32/Main.htm

映射文件Pointer.map

2011/06/30 留下评论

值得注意的是,如果你只在VC Project Setting对话框中打开Generate mapfile,还是不够的。因为你一定还要输出程序代码地址和源代码行号!!这非常的重要!

要得到这些信息,请在Project Options对话框中键入“/mapinfo:lines /mapinfo:exports”。请你一定要养成这种习惯!因为这不是默认设置。

我们得到的map文件大致如下,我删节了大多数输出:

Pointer

(应用程序名)

Timestamp is 3d4407a7 (Sun Jul 28 23:03:03 2002)

(时间戳)

Preferred load address is 00400000

(最佳装载基地址。非常重要的一个数据。不过一般都是这个数。)

Address         Publics by Value              Rva+Base     Lib:Object

0001:00000250       _main                      00401250 f   Pointer.obj

(_main的虚地址)

Line numbers for .\Debug\Pointer.obj(E:\ Pointer\Pointer.cpp) segment .text

12 0001:00000250    14 0001:00000268    15 0001:0000026f    16 0001:00000276

18 0001:0000027f    20 0001:00000291    23 0001:000002a4    24 0001:000002a6

(这就是我们的Pointer.cpp所对应的程序代码行号和相对虚拟地址的对应表)

我们可以从中看到,最佳装载基地址是0x00400000,_main的虚地址是0x00401250,而0001:00000250又是什么意思呢?

0x00000250就是_main的相对虚拟地址(RVA)。

0x00010000就是PE头文件的大小,一般都是这个数。

所以虚地址就是这么算出来的:

0x00401250 = 0x00400000     + 0x00010000     +  0x00000250

虚地址      = 最佳装载基地址 + PE头文件的大小 + 相对虚拟地址(RVA)

通过_main的RVA的计算,我们也就知道了怎么计算崩溃地址0x00401279的RVA,是0x00000279,对吧?

然后,在这个MAP映射文件的“Line numbers for .\Debug\Pointer.obj(E:\ Pointer\Pointer.cpp) segment .text”这个行号段中查找这个地址。如你所看到的,只有16行对应的00000276和18行对应的0000027F,没有00000279呀?

没有17行的对应关系,说明17行是空行。

那么00000279就一定是16行的了!这样你不用看那个程序员的代码,就可以通知他:崩溃发生在你的Pointer.cpp的第16行了!很酷吧!

利用pexports和MSVC,制作在MSVC下能链接的MingW编译的动态库

2011/06/30 留下评论

以下为BAT文件的内容

rem 必须要先安装MinGW
rem 通过下面的命令,来设置环境变量,并且只在本过程中有效
set path==%path%;C:\MinGW\bin\
pause;

rem 执行下面的命令来编译,参考:http://blog.csdn.net/shania_wang/archive/2010/10/26/5966492.aspx
mkdir dll_bin
gcc -O2 -shared -Wall -Wl,–export-all-symbols -mpreferred-stack-boundary=2 -march=i386 -falign-functions=0 -fno-strict-aliasing -DTCC_TARGET_PE -DLIBTCC -o dll_bin\libtcc.dll tcc.c
pause

rem 从dll导出 def文件, 参考:http://www.emmestech.com/software/pexports-0.43/download_pexports.html
pexports dll_bin\libtcc.dll > dll_bin\libtcc.def
pause

rem 调用VC的工程制造引出库,MinGW 的 dlltool制造出来的在release版本下无法引入
call “C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT”
LIB /def:dll_bin\libtcc.def /machine:i386 /out:dll_bin\libtcc_imp.lib

pause

 

摘自:http://www.cppblog.com/woaidongmao/archive/2011/06/30/149816.html

Codejock.Xtreme.Toolkit.Pro V15.0.1 VC6下的编译问题

2011/03/24 留下评论

1. Dialog type “Hello word!” application.

2. Fatal Error message:

Compiling…StdAfx.cppAutomatically linking with ToolkitPro1501vc60SD.libc:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(61) : fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit        c:\program files\microsoft visual studio\vc98\mfc\include\afxtempl.h(331) : see reference to function template instantiation ‘void __stdcall ConstructElements(class CXTPReportRecordItemControl ** ,int)’ being compiledError executing cl.exe.

3. 解决办法:

添加定义

#define _XTP_EXCLUDE_CALENDAR

#define _XTP_EXCLUDE_REPORTCONTROL

还不知VC6下为什么不能包含CALENDAR和REPORTCONTROL功能。

用定时器和消息机制完成类似UI线程和工作线程的触发机制

2010/01/22 留下评论
网上太多关于这种不阻塞消息的延时操作,但是绝大多数都是一知半解的抄写过来的,根本不能使用。
以下的代码已经经过验证,可以完成延时的要求,并能够响应WM_CLOSE和WM_SYSCOMMAND (SC_CLOSE)的退出处理。
static UINT USER_REGISTER_MESSAGE = ::RegisterWindowMessage("Time Up");
static UINT USER_REGISTER_CLOSE_MESSAGE = ::RegisterWindowMessage("CLOSE");
void CMessageDlg::OnButton1() 
{
MSG msg;
for(int i=0; i<2; i++){
//SetTimer(1,2000,NULL);
while(TRUE){
if(::PeekMessage(&msg, NULL,  0, 0, PM_NOREMOVE))   {
//TRACE2("%04x %04xn",HIWORD(msg.message),LOWORD(msg.message));
if(LOWORD(msg.message) == USER_REGISTER_MESSAGE){
GetMessage(&msg,NULL,NULL,NULL);
break;
}
if(msg.message == USER_REGISTER_CLOSE_MESSAGE)  
{
GetMessage(&msg,NULL,NULL,NULL);
PostQuitMessage(0);
return;
}
if(GetMessage(&msg,NULL,NULL,NULL)){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
MessageBox("OK");
}
}
void CMessageDlg::OnTimer(UINT nIDEvent) 
{
this->PostMessage(USER_REGISTER_MESSAGE,0,0);
KillTimer(1);
CDialog::OnTimer(nIDEvent);
}
LRESULT CMessageDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
if(message == WM_CLOSE ||
(message == WM_SYSCOMMAND && (wParam & 0xfff0) == SC_CLOSE))
{
PostMessage(USER_REGISTER_CLOSE_MESSAGE,0,0);  
return 0;
} else if(message == USER_REGISTER_CLOSE_MESSAGE){
PostQuitMessage(0);
}
return CDialog::DefWindowProc(message, wParam, lParam);
}