2010年9月6日
#
如何当前操作系统是不是64位?如何判断当前应用程序是否在Wow64下运行?
首先什么是Wow64?很多朋友一看到64就认为这个方法是判断当前系统是否是64bit的,其实不然。Wow64是Windows-On-Windows64的意思,它是指在64位的操作系统上(不是指64位的CPU)运行32位应用程序的兼容平台。
下面是MSDN中一段IsWow64的应用程序:
BOOL IsWow64()
{
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS fnIsWow64Process;
BOOL bIsWow64 = FALSE;
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress( GetModuleHandle(_T("kernel32")), "IsWow64Process");
if (NULL != fnIsWow64Process)
{
fnIsWow64Process(GetCurrentProcess(),&bIsWow64);
}
return bIsWow64;
}
下面的代码用来检测这个程序的结果:
if( IsWow64() == TRUE )
{
_tprintf(_T("IsWow64() == TRUE\n"));
}
else
{
_tprintf(_T("IsWow64() == FALSE\n"));
}
让我们编译一下这个程序。
我们需要的是64位的操作系统,比如XP64bit,Windows 2008 R2等都是64bit操作系统。
在64位的操作系统上运行的kernel32.dll中,将会实现IsWow64Process方法,而在32位系统中提供的kernel32.dll中则没有提供相关函数的实现。
比较迷惑人的则是bIsWow64,其实仔细看MSDN中的Remark,会发现:
If the application is a 64-bit application running under 64-bit Windows, the Wow64Process parameter is set to FALSE.也就是说64位应用程序跑在64位的操作系统上,bIsWow64的值将是FALSE而不是TRUE。
因此我们需要分别将我们的程序编译成Win32平台和x64平台的,如果你用Visual Studio进行编译,默认安装则只包含32位的编译器/链接器,即便你是在64位操作系统上安装,也是一样的。你需要在VC++节点下勾选x64选项才可以,Itanium则需要在Server平台下安装才可勾选。然后在编译的时候,分别选择Win32和x64进行编译。
编译后,运行,结果如我们分析的一样:
在64位系统上运行Win32编译配置的结果是IsWow64() == TRUE,而x64编译配置的结果是IsWow64() == FALSE。
如果想要知道当前系统是否是64位的,则可以通过下面的方法:
BOOL Is64bitSystem()
{
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ||
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
{
return TRUE;
}
else
{
return FALSE;
}
}
注意:需要注意是GetNativeSystemInfo 函数从Windows XP 开始才有, 而 IsWow64Process 函数从 Windows XP with SP2 以及 Windows Server 2003 with SP1 开始才有。
2010年9月5日
#
摘要: http://software.intel.com/zh-cn/articles/intel-guide-for-developing-multithreaded-applications/ 英特尔® 多线程应用开发指南 提交新文章 Published On : 2010年02月25日 20:00 评级 请登录后评级!当前分数: 0 由 0 用户 请登录后评级!当前分数: 0 ...
阅读全文
2010年9月4日
#
目的:测试MAX_PATH路径与文件名的关系。
结论:MAX_PATH代表从盘符开始到文件名结尾的C字符串长度(长度+1)的最大长度。也就是假设C:\a.txt共8个字符,长度为9,MAX_PATH通常为260,其中这个文件全名的长度不能大于260。
测试代码:

#include "stdafx.h"
#include <atlbase.h>
#include <windows.h>
#include <atlfile.h>
#include <atlstr.h>
#include <iostream>
#include <string>
BOOL IsFileExist( LPCTSTR lpszFileName )
{
DWORD dwAttr = ::GetFileAttributes( lpszFileName );
if ( dwAttr == 0xFFFFFFFF )
{
return FALSE;
}
if ( ( dwAttr & FILE_ATTRIBUTE_DIRECTORY ) > 0 )
{
return FALSE;
}
return TRUE;
}
BOOL DeleteFiles( LPCTSTR lpszPath )
{
TCHAR szFrom[_MAX_PATH+1] = {_T( '\0' )};
lstrcpy( szFrom , lpszPath );
SHFILEOPSTRUCT shf;
memset( &shf, 0, sizeof( SHFILEOPSTRUCT ) );
shf.hwnd = NULL;
shf.pFrom = szFrom;
shf.wFunc = FO_DELETE;
shf.fFlags = FOF_NOCONFIRMMKDIR | FOF_NOCONFIRMATION |
FOF_NOERRORUI | FOF_SILENT;
return SHFileOperation( &shf ) == 0;
}
BOOL WriteBinaryBytesToFile( LPCTSTR fileName, unsigned char* data,
unsigned int datasize , BOOL bAppend )
{
CAtlFile file;
if( !bAppend && IsFileExist( fileName ))
DeleteFiles( fileName );
HRESULT ret = file.Create( fileName, FILE_WRITE_DATA, FILE_SHARE_WRITE, bAppend?OPEN_ALWAYS:CREATE_ALWAYS );
if ( !SUCCEEDED( ret ) )
return FALSE;
if( bAppend )
{
file.Seek( 0, FILE_END );
}
unsigned char *pos = data;
while( datasize > 0 )
{
DWORD dwWrite = 0;
if ( file.Write( pos , datasize , &dwWrite ) != S_OK )
{
file.Close();
return FALSE;
}
datasize -= dwWrite;
pos += dwWrite;
}
file.Close();
return TRUE;
}
BOOL GCreateFile(std::string& fileNamePath,
std::string& fileNameExt,
int shortNameLength,
std::string& data)
{
char c[] = "a";
std::string fileName;
fileName.append(fileNamePath);
while( shortNameLength-- )
{
fileName.append(c);
++*c;
if( *c > 'z' )
{
*c = 'a';
}
}
fileName.append(fileNameExt);
std::cout << "fileName:" << fileName << std::endl;
std::cout << "fileName.size():"<< fileName.size() << std::endl;
std::cout << "MAX_PATH" << MAX_PATH << std::endl;
if( WriteBinaryBytesToFile(fileName.c_str(), (unsigned char*)data.data(), data.size(), FALSE ) )
{
std::cout << "++++++++++++++WriteBinaryBytesToFile successful.++++++++++++++" << std::endl;
return TRUE;
}
else
{
std::cout << "==============WriteBinaryBytesToFile error==============." << std::endl;
return FALSE;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
std::string fileNamePath = "E:\\MyCPlusProject\\TestFileNameMaxLength\\TestFileNameMaxLength\\Output\\";
std::string fileNameExt = ".txt";
std::string data("This is a content.");
int shortNameLength;
shortNameLength = MAX_PATH - fileNameExt.size() - fileNamePath.size();
GCreateFile(fileNamePath, fileNameExt, shortNameLength, data);
std::cout << "------------------" << std::endl;
shortNameLength = MAX_PATH - fileNameExt.size() - fileNamePath.size() - 1;
GCreateFile(fileNamePath, fileNameExt, shortNameLength, data);
return 0;
}
提示:右键项目属性,将字符集设置为“未设置”。
最近遇到一个跟Windows(不是指操作系统,而是一个::CreateWindow的结果)有关的问题。
情况是这样的,通常的应用程序内的事件传递一般场景都是类似在窗体A上点击按钮1,弹出一个窗体B。面对这样的场景只要::SetWindowActive(HWND wnd)即可,这里其实有个隐含的前提,就是wnd的父窗口是出于TOP的状态,也就是它的父窗口是置顶的,也就是我们能够在界面上看到它,否则你的其他置顶窗口将依旧置顶。
下面的代码示意了如何将窗口置顶,因为也没有对各个方法做深入分析,所以就不多发表言论了:
/*场景:
目标:将子窗口放到置顶(且是HWND_TOP)模式
说明:hMainWnd是主窗口,m_pMMessageWnd->m_hWnd是子窗口
*/
/*1、将窗口从后台直接提到最前方,需要先将主窗口移上来。*/
HWND hMainWnd = CFramework::GetInstance()->GetMainWnd();
if( hMainWnd != NULL )
{
SetForegroundWindow(hMainWnd);
BringWindowToTop(hMainWnd);
SetActiveWindow(hMainWnd);
SetWindowPos( hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
}
/*2、将子窗口置顶*/
if( m_pMMessageWnd != NULL ) /* true */
{
SetForegroundWindow(m_pMMessageWnd->m_hWnd);
BringWindowToTop(m_pMMessageWnd->m_hWnd);
SetActiveWindow(m_pMMessageWnd->m_hWnd);
SetWindowPos( m_pMMessageWnd->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
SetWindowPos( m_pMMessageWnd->m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
}
/*3、放在后面的原因是避免子窗口还未弹出,点击窗体外的时候被放到后面去,所以等窗口出来后再取消置顶*/
if( hMainWnd != NULL )
{
SetWindowPos( hMainWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
}
/*4、避免被主窗口给压了*/
if( m_pMMessageWnd != NULL ) /* true */
{
SetWindowPos( m_pMMessageWnd->m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
SetWindowPos( m_pMMessageWnd->m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW );
}
2010年8月28日
#
转载自:http://developer.51cto.com/art/200702/39608.htm
动态连接库的创建步骤:
一、创建Non-MFC DLL动态链接库
1、打开File —> New —> Project选项,选择Win32 Dynamic-Link Library —>sample project —>工程名:DllDemo
2、新建一个.h文件DllDemo.h
#ifdef DllDemo_EXPORTS
#define DllAPI __declspec(dllexport)
#else
#define DllAPI __declspec(dllimport)
extern "C" //原样编译
{
DllAPI int __stdcall Max(int a,int b); //__stdcall使非C/C++语言内能够调用API
}
#endif
3、在DllDemo.cpp文件中导入DllDemo.h文件,并实现Max(int,int)函数
#include "DllDemo.h"
DllAPI int __stdcall Max(int a,int b)
{
if(a==b)
return NULL;
else if(a>b)
return a;
else
return b;
}
4、编译程序生成动态连接库
二、用.def文件创建动态连接库DllDemo.dll
1、删除DllDemo工程中的DllDemo.h文件。
2、在DllDemo.cpp文件头,删除 #include DllDemo.h语句。
3、向该工程中加入一个文本文件,命名为DllDemo.def并写入如下语句:
LIBRARY MyDll
EXPORTS
Max@1
4、编译程序生成动态连接库。
动态链接的调用步骤:
一、隐式调用
1、建立DllCnslTest工程
2、将文件DllDemo.dll、DllDemo.lib拷贝到DllCnslTest工程所在的目录
3、在DllCnslTest.h中添加如下语句:
#define DllAPI __declspec(dllimport)
#pragma comment(lib,"DllDemo.lib") //在编辑器link时,链接到DllDemo.lib文件
extern "C"
{
DllAPI int __stdcall Max(int a,int b);
}
4、在DllCnslTest.cpp文件中添加如下语句:
#include "DllCnslTest.h"//或者 #include "DllDemo.h"
void main()
{
int value;
value = Max(2,9);
printf("The Max value is %d\n",value);
}
5、编译并生成应用程序DllCnslTest.exe
二、显式调用
1、建立DllWinTest工程。
2、将文件DllDemo.dll拷贝到DllWinTest工程所在的目录或Windows系统目录下。
3、用vc/bin下的Dumpbin.exe的小程序,查看DLL文件(DllDemo.dll)中的函数结构。
4、使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针。
例:
typedef int(*lpMax)(int a,int b); //此语句可以放在.h文件中
5、通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄。
例:
HINSTANCE hDll; //声明一个Dll实例文件句柄
hDll = LoadLibrary("DllDemo.dll");//导入DllDemo.dll动态连接库
6、通过GetProcAddress()函数获取导入到应用程序中的函数指针。
例:
lpMax Max;
Max = (lpMax)GetProcAddress(hDLL,"Max");
int value;
value = Max(2,9);
printf("The Max value is %d",value);
7、函数调用完毕后,使用FreeLibrary()卸载DLL文件。
FreeLibrary(hDll);
8、编译并生成应用程序DllWinTest.exe
注:显式链接应用程序编译时不需要使用相应的Lib文件。
下载(Visual Studio 2008验证通过):http://www.cppblog.com/Files/mymsdn/DllCnsTest.7z
2010年8月11日
#
禁止类成员复制,其核心就在于不允许类外部看见复制函数,包括“拷贝构造函数”、“operator =重载”。
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
private: \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&)
禁止隐式构造,则可以将默认构造函数隐藏起来,在大多数编译器中也可以对构造函数增加explicit关键字来避免隐式构造。
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
private: \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
更多解释详见《More Effective C++》
2010年7月22日
#
__declspec关键字
// keyword__declspec.cpp : 定义控制台应用程序的入口点。
//
// ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/kernel_d/hh/Kernel_d/64bitAMD_6db3322a-fe6d-4287-9eda-a9c1378e715d.xml.htm
// The sizeof value for any structure is the offset of the final member,
// plus that member's size, rounded up to the nearest multiple of the largest
// member alignment value or the whole structure alignment value,
// whichever is greater.
#include "stdafx.h"
__declspec( align( 32) ) struct Struct__declspec_1
{
int a;
int b;
};
__declspec( align( 32) ) struct Struct__declspec_2
{
__declspec( align( 64) ) int a;
int b;
};
__declspec( align( 8 ) ) struct Struct__declspec_3
{
int a; //4 bytes
int b; //4 bytes
int c; //4 bytes
};
__declspec( align( 8 ) ) struct Struct__declspec_4
{
int a; //4 bytes
int b; //4 bytes
};
struct StructNormal
{
int a; //4 bytes
int b; //4 bytes
int c; //4 bytes
};
int _tmain(int argc, _TCHAR* argv[])
{
printf( "sizeof Struct__declspec_1 is %d.\n", sizeof( Struct__declspec_1 )); //32
printf( "sizeof Struct__declspec_2 is %d.\n", sizeof( Struct__declspec_2 )); //64
printf( "sizeof Struct__declspec_3 is %d.\n", sizeof( Struct__declspec_3 )); //16
printf( "sizeof Struct__declspec_4 is %d.\n", sizeof( Struct__declspec_4 )); //8
printf( "sizeof StructNormal is %d.\n", sizeof( StructNormal )); //12
return 0;
}
2010年7月6日
#
摘要: 和大多数内存管理的初衷一致,希望能够控制内存分配和回收,减少内存碎片,且通常这样的内存都会预开一段连续内存空间,然后我们自己来管理这段内存。当然通常这样的需求都很合理,但是实现起来则通常不能完美,比如:效率、算法的选择、如何减少内存碎片、跟踪管理内存分配、性能检测、对系统内存使用的统计、垃圾回收等。下面是我近期实现的一个非常简陋的程序,甚至可能连基本的要求都无法达到,大家帮忙看看,它究竟有多少缺点...
阅读全文
2010年7月2日
#
今天在VS2008下编译VS自带Sample中的一个例子,TstCon,因为之前的机器装的是XP系统,该程序曾成功编译过,不过今天在Windows Server 2008 R2下打开失败,在朋友的Windows 7 Ultimate下打开也失败,试用以管理员身份运行,失败,试用修改兼容性选项为Windows XP SP3/SP2方式,均失败。
其实这个时候可能是一些Vista以上版本的OS所提供的新功能引起的限制。就当前的这个例子而言,是因为编译的时候,启用用户帐户控制(UAC)默认为“是”所致,将解决方案内所有工程选中,右键属性,修改“配置属性”->“链接器”->“清单文件”->“启用用户帐户控制(UAC)”为“否”,重新生成解决方案,即可。

2010年6月30日
#
准确地说还是经验不足,这么简单的事居然想了好几分钟,当然也要怪VS在没有重新生成前的诡异现象。
今晚在类中加入两个数组用来做计数,因为之前代码有所改动,VS编译(增量)的结果居然出现了无数次的程序崩溃,害我一度怀疑是不是我的数组写的有问题。囧。最后无奈之下,点了重新生成,居然顺利通过了,很生气,愤怒中。
但是另外却发现了一个问题,也就是当size_t用作循环的时候。因为以前都是用int做循环的,现在换成unsigned int(也就是size_t)后,一下子没反应过来,就顺手这么写了:
for( size_t i = MAX - 1; i >= 0; --i)
{
//……
}
乍一看似乎没啥问题,因为我循环内的代码是删除资源的,因此程序也频频崩溃。
step over的结果才让人惊讶,因为当size_t i = 0的时候,--i的结果是无穷大,而无穷大则肯定满足i>=0的条件,所以当我们期待程序停住的时候,程序是不会停住的。
修正的方式:
1、使用正向遍历。
2、增加判断条件(i>=0 && i < MAX),但这里也可能存在问题,因为size_t可能被定义为unsigned int,但是MAX可能是个更大的数,比如unsigned long long,当然这样的比较不是很有意义,或者会实现一些转换,但是如果这种情况发生的话,程序可能还是会通过一个随机的i进入到一个未知的空间中,从而造成崩溃。而且增加判断条件也使得程序的运行成本提高。