想用windows PSAPI中的EnumPageFiles函数获取页面文件的列表及使用情况,查到在MSDN中的声明是这样的:
BOOL WINAPI EnumPageFiles(
__out PENUM_PAGE_CALLBACK pCallbackRoutine,
__in LPVOID lpContext
);
看到第一个参数是__out,感觉非常奇怪,它要输出做什么用呢?想来应该是自己定义的一个函数,然后对每一个页面文件都调用该函数,因为在MSDN中PENUM_PAGE_CALLBACK 的定义是这样的:
BOOL CALLBACK EnumPageFilesProc(
[in] LPVOID pContext,
[in] PENUM_PAGE_FILE_INFORMATION pPageFileInfo,
[in] LPCTSTR lpFilename
);
很容易想到在自定义的PENUM_PAGE_CALLBACK 中通过传入的参数PENUM_PAGE_FILE_INFORMATION 去获取页面文件的使用情况,但EnumPageFiles的第
一个参数无论如何不应该是输出,于是我试了一下,定义一个变量,该变量没有初始化的时候传给EnumPageFiles,
……
PENUM_PAGE_FILE_CALLBACK pf ; // = &OnEachPageFile;
if( EnumPageFiles(pf , NULL) ){
return -1;
}
……
结果在VS中调试时会有异常抛出,是由于传入的变量没有初始化,显然该参数不应该是输出,否则没有理由要求参数必须进行初始化的,所以这个声明应该是有问题的,而事实上在psapi.h头文件的声明中并没有给EnumPageFiles的参数添加任何修饰词,例如__in或__out等,而其中绝大部分函数是有这些修饰词的,显然与MSDN文档不一致,而PENUM_PAGE_FILE_CALLBACK其实就是个宏,其定义及实际定义如下:
#define PENUM_PAGE_FILE_CALLBACK PENUM_PAGE_FILE_CALLBACKA
#define EnumPageFiles EnumPageFilesA
typedef BOOL (* PENUM_PAGE_FILE_CALLBACKA) (LPVOID pContext, PENUM_PAGE_FILE_INFORMATION pPageFileInfo, LPCSTR lpFilename);
这ASCII版的定义,本文只说ACII版的,UNICODE版的代码类似。可见EnumPageFiles 与MSDN文档中的定义也不一致。根据头文件中的定义,定义自己的EnumPageFilesProc,像这样:
BOOL OnEachPageFile(LPVOID pContext,
PENUM_PAGE_FILE_INFORMATION pPageFileInfo,
LPCTSTR lpFilename)
{
……
}
则在运行时会发生内存非法访问的异常,所以怀疑是头文件的声明与DLL中的实现不一致,关健就在于一个CALLBACK的修饰,因为CALLBACK其实是一个宏定义
#define CALLBACK __stdcall
而VC中C/C++的默认函数调用方式是__cdecl的,DLL中的实现是__stdcall,这会导致调用函数的堆栈的维护方式不同,__cdecl是用函数调用者清理堆栈,而__stdcall是windows API的函数调用方式,它是由被调用函数清理堆栈,所以如果声明与实现不一致会导致堆栈的非访问。
于是试着去改psapi.h中的声明,将PENUM_PAGE_FILE_CALLBACKA的定义改为:
typedef BOOL (CALLBACK * PENUM_PAGE_FILE_CALLBACKA) (LPVOID pContext, PENUM_PAGE_FILE_INFORMATION pPageFileInfo, LPCSTR lpFilename);
然后再测试,一切正常,当然自定义的函数的定义中也要有CALLBACK的修饰,完整代码如下:
#include <windows.h><br>#include <psapi.h><br>#pragma comment(lib, "psapi") <p></p><p>#include <string><br>#include <vector><br>#include <iostream><p>using std::string;<br>using std::vector; </p>
<p></p>
<p>struct SwapInfo{<br> string name;<br> string path;<br> string type;<br> long long free;<br> long long size;<br> long long used;<br>}; </p>
<p></p>
<p></p>
<p>BOOL CALLBACK OnEachPageFile(LPVOID pContext,<br> PENUM_PAGE_FILE_INFORMATION pPageFileInfo,<br> LPCTSTR lpFilename)<br>{<br> SwapInfo si;<br> vector<swapinfo>* ls = static_cast<vector>*>(pContext); <p> si.free = pPageFileInfo->TotalSize - pPageFileInfo->TotalInUse;<br> si.name = lpFilename;<br> si.path = lpFilename;<br> si.size = pPageFileInfo->TotalSize;<br> si.type = "Pagefile";<br> si.used = pPageFileInfo->TotalInUse;<br> ls->push_back(si);<br> return TRUE;<br>} </p>
<p></p>
<p>int get_swap_info(vector<swapinfo> & swapinfo)<br>{<br> vector<swapinfo> ls;<br> SwapInfo info;<br> PENUM_PAGE_FILE_CALLBACK pf = &OnEachPageFile;<br> ls.clear();<br> if( EnumPageFiles(pf, &ls) ){<br> swapinfo.clear();<br> swapinfo = ls;<br> return 0;<br> }<br> return -1; <p>} </p>
<p></p>
<p>int main( int argc, char* argv[])<br>{<br> vector<swapinfo> pgfiles; <p> if( get_swap_info(pgfiles) != 0){<br> std::cerr return -1;<br> }<br> std::cout for( vector<swapinfo>::const_iterator it = pgfiles.begin(); it != pgfiles.end(); ++it){<br> std::coutnameusedsize }<br> return 0;<br>}</swapinfo></p></swapinfo></p></swapinfo></swapinfo></p></vector></swapinfo></p></iostream></vector></string></p></psapi.h></windows.h>
输出结果:
F:/Projects/EnumPageFiles/Debug>EnumPageFiles.exe
Pagefiles:
C:/pagefile.sys: 14532/131072 pages
D:/pagefile.sys: 14579/32768 pages
E:/pagefile.sys: 14310/32768 pages
有一点值得说明,这里的EnumPageFiles函数会自动对每一个页面文件都调用一次OnEachPageFile,不论有多少个页面文件只需要调用一次EnumPageFiles。
结论: MSDN中绝大部分说明是正确的,除了EnumPageFiles第一个参数的修饰__out,应该使用__in,psapi.h中的声明错误,应该使用MSDN中的声明。
分享到:
相关推荐
psapi.lib复制到vc++6.0的lib目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\Lib),psapi.h复制到Include目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\Include)便可使用,psapi.dll...
psapi.h头文件 Psapi.Lib Psapi.dll psapi.lib复制到vc++6.0的lib目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\Lib),psapi.h复制到Include目录下(如:C:\Program Files\Microsoft Visual Studio\...
psapi.h 头文件和 psapi.dll 使用说明 1、psapi.lib复制到vc++6.0的lib目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\Lib); 2、psapi.h复制到Include目录下(如:C:\Program Files\Microsoft ...
包含psapi.h、Psapi.Lib、psapi.dll文件,拷贝到工程目录,添加#include <psapi.h>#pragma comment(lib,"psapi.lib")代码即可。
psapi.dll psapi.lib psapi.h
包含<psapi.h>和<psapi.lib> psapi.lib复制到vc++6.0的lib目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\Lib),psapi.h复制到Include目录下(如:C:\Program Files\Microsoft Visual Studio\VC98\...
process status API ,是获取系统状态的函数集合.包含psapi.h psapi.lib 两个API 文件
psapi.h和 psapi.lib 和 psapi.dll VC 6.0 下可能没有这个文件,分享使用!!
psapi包含psapi.h、psapi.dll、psapi.dll以及说明文档。
vc需要的psapi.h和psapi.lib
psapi.dll 复制到C:\Program Files\Microsoft Visual Studio\VC98\Lib psapi.h 复制到 C:\Program Files\Microsoft Visual Studio\VC98\Include
是psapi的资源文件,包含了psapi.h、psapi.dll、psapi.lib
PSAPI.H Psapi.Lib 我测试过可用。 lib文件放在: C:\Program Files\Microsoft Visual Studio\VC98\Lib下。 .h文件放在: C:\Program Files\Microsoft Visual Studio\VC98\Include下。 解决c++编译找不到这两个文件...
VC编程psapi.h 全套文件经典代码VC programming psapi.h complete file classic code
包含文件:psapilib psapi.h
psapi.h头文件,C++编程用的资源包
包含: psapi.h psapi.dll psapi.lib
包含Psapi.h Psapi.lib两个文件!是编程爱好者难得的学习资料!
vc需要的psapi.h
psapi全套