今天包装Ini文件的读写,出现一个令人困惑的问题:我将C:\windows\system.ini复制到D:的根目录下,添加、修改了几个值,然后使用GetPrivateProfileString函数读取,发现值根本没有变,但是实际文件改变了。我把D:下的system.ini改名为123.Ini,读写就正常了。困惑中……难道GetPrivateProfileString函数中的文件名参数是吃干饭的?!而其他名字的Ini却很正常?还是我得机器有问题????我的机器是Xp+Sp2+Vc 6.0。
最近好像常常看到有人问如何调试内存泄漏的问题,于是我写下本文,抛砖引玉……
首先,应该是MFC报告我们发现内存泄漏。注意:要多运行几次,以确定输出的内容不变,特别是{}之间的数值,不能变,否则下面的方法就不好用了。
我们来看看:
F:\CodeSample\Test\TestPipe\LeakTest\MainFrm.cpp(54) : {86} normal block at 0x00422E80, 10 bytes long.
Data: < > 1F 1F 1F 1F 1F CD CD CD CD CD
F:\CodeSample\Test\TestPipe\LeakTest\MainFrm.cpp(54) 告诉我们MFC认为是在该文件的54行,发生了内存泄漏。你双击改行就可以转到该文件的54行了。但是有时候这一信息并不能用来准确判断,比如:MFC可能报告Strcore.cpp文件的某行,实际上这是CString的实现函数,此时并不知道什么时候发生了内存泄漏。
此时我们需要更多的信息。那么我们看看紧接其后的:
{86} normal block at 0x00422E80, 10 bytes long.
Data: < > 1F 1F 1F 1F 1F CD CD CD CD CD
它告诉我们:在第86次分配的内存没有释放,一共有10字节,内容移16进制方式打印给我们看。
有了这些信息,我们可以开始调试内存泄漏了。
按下F10在程序的刚开始处,停下来,打开Watch窗口:
在Watch窗口中输入:
{,,msvcrtd.dll}_crtBreakAlloc
然后更改值为上文提到的分配次数:86
接着按下F5继续,然后在第86次分配的时候会发生中断:
然后我们打开堆栈窗口:
往回查看最近我们自己的代码,双击堆栈我们自己的函数那一层,上图有绿色三角的那一层。就定位到泄漏时分配的内存了。
之后,就是看你的编码功底了。
Vc编译版本时,手工管理版本的增加比较麻烦,所以自己写了个小工具,用来自动增加版本。首先要在你的工程里设定一下。下面图示自动增加Release时的版本。
首先打开Release的工程设定,切换到Post-build step页面。在Post-build Command(s)里新建一行命令,输入要执行的命令,本文是:
E:\Tools\AutoVersion.exe /Comments "Powered By King"
当然你也可以增加其他的命令。
然后编译Release版本,你会在输出窗口看到:
那么此时的文件属性就是:
没错,文件版本显示的是1003,这是上一次的属性。因为AutoVersion.exe是在编译完成后才开始更改版本的,所以显示的总会延迟一次。
好了现在来介绍AutoVersion.exe的参数:
/ResFile C:\Work\Work.Rc 指定特定的资源文件,用于资源文件不是放在工程目录下时,或者工程文件下有多个资源文件时
/Buckup 参数告诉在改变时现在资源所在的路径备份一下,备份文件是添加.bak扩展名。
/IncMain 自动增加主文件版本号。
/Comments "This is Comment"
/CompanyName "My Company"
/FileDescription "FileDescription"
/InternalName "FileName"
/LegalCopyright "Copyright 2003"
/LegalTrademarks "LegalTrademarks"
/OriginalFilename "FileName"
/ProductName "ProductName"
/SpecialBuild "SpecialBuild"
以上参数必须在资源文件中存在(除了Comments),另外如果资源里存在PrivateBuild值,那么PrivateBuild会被改成编译时间(比如2005-12-9 16:13:34)
AutoVersion.exe可以在我的blog下载:
AutoVersion下载声明:
本工具只是本人游戏之做,使用时最好要备份资源文件(.rc),如果出现问题本人概不负责。使用请自己考虑清楚。
void CTrayDlg::OnButton1()
{
// TODO: Add your control notification handler code here
HWND wd=::FindWindow("Shell_TrayWnd",NULL);
if (wd==NULL)
{
MessageBox("Error1");
return;
}
HWND wtd=FindWindowEx(wd,NULL,"TrayNotifyWnd",NULL);
if (wtd==NULL)
{
MessageBox("Error2");
return;
}
HWND wd1=FindWindowEx(wtd,NULL,"ToolbarWindow32",NULL);
if (wd1==NULL)
{
MessageBox("Error3");
return;
}
DWORD pid;
pid=0;
GetWindowThreadProcessId(wd1,&pid);
if (pid==NULL)
{
MessageBox("Error4");
return;
}
HANDLE hd=OpenProcess(PROCESS_QUERY_INFORMATION ¦ PROCESS_ALL_ACCESS ,true,pid);
if (hd==NULL)
{
MessageBox("Error6");
return;
}
int num=::SendMessage(wd1,TB_BUTTONCOUNT ,NULL,NULL);
int i;
unsigned long n;
TBBUTTON p,*pp;
CString x;
wchar_t name[256];
unsigned long whd,proid;
CString temp;
TBBUTTON *sp;
sp= (TBBUTTON *)0x20f00; //这里应该改成用VirtualAllocEx分配内存否则有可能出错,不过人懒,就先这么着吧
for(i=0;i<num;i++)
{
::SendMessage(wd1,TB_GETBUTTON,i,(LPARAM)sp);
pp=&p;
ReadProcessMemory(hd,sp,pp,sizeof(p),&n);
// x.Format("%x %x %x %x %x %x",p.iBitmap,p.idCommand,p.fsState,p.fsStyle, p.dwData, p.iString);
name[0]=0;
if (p.iString!=0xffffffff)
{
try
{
ReadProcessMemory(hd,(void *)p.iString,name,255,&n);
name[n]=0;
}
catch()
{
}
// x+=" ";
// x+=name;
temp=name;
try
{
whd=0;
ReadProcessMemory(hd,(void *)p.dwData,&whd,4,&n);
}
catch()
{
}
proid=0;
GetWindowThreadProcessId((HWND)whd,&proid);
x.Format("位置=%d 名称=%s 窗口句柄=%08x 进程ID=%08x",
i,(LPCTSTR )temp,whd,proid);
m_list.AddString(x);
}
}
}
使用SoftIce调试关键是建立符号表,和让SoftIce加载符号表。
建立符号表可以用下面的命令行:
C:\Program Files\Compuware\DriverStudio\SoftICE\nmsym.exe /TRANS:SYMBOLS,PACKAGE,ALWAYS F:\CodeSample\Test\hook\Debug\hOOKDLL.DLL /OUTPUT:F:\CodeSample\Test\hook\Debug\HOOK.NMS /SOURCE:"E:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC";"E:\Program Files\Microsoft Visual Studio\VC98\MFC\SRC";F:\CodeSample\Test\hook
然后双击生成的符号表,让SoftIce载入。
之后就可以在SoftIce调试界面里使用了。
转:使用SoftIce调试free build版的Driver方法
标题:使用SoftIce调试free build版的Driver方法
创建:2006/07/24
--------------------------------------------------------------------------
1. 使用IDA生成map文件。
2. 使用Visual Studio中的mapsym.exe生成sym文件。
e.x:
mapsym -m test.map
产生test.sym文件
3. 使用Driver Studio中SoftIce目录下的nmsym.exe生成nms文件。
e.x:
nmsym test.sym
产生test.nms文件
4. 加载test.nms文件,Ctrl-d呼出sice,就可以根据ida里的标签、变量等进行设置
断点了。
e.x:
nmsym /sym:test.nms
--------------------------------------------------------------------------
windbg symbolsetting:
set _NT_SYMBOL_PATH=srv*DownstreamStore*http://msdl.microsoft.com/download/symbols
srv*E:\Cache\Symbols*http://msdn.microsoft.com/download/symbols;
--------------------------------------------------------------------------
再装vmware tools ,选择自定义安装项,只安装svga driver,next……finish。
找到虚拟的操作系统的vmx文件在最后添加以下两行代码:
vmmouse.present = "FALSE"
svga.maxFullscreenRefreshTick = "5"
ctlr+d 呼出正常。但返回后,键盘失灵。这个以前到是碰到过,将softice安装程序目录下的i8042prt.sys文件覆盖system32\drivers下同名文件。这下可以了.
Win32 备份 API 函数(
BackupRead、BackupWrite 等等),可被用来枚举文件中的流。不过,它们用起来有点怪异,而且看上去更像一个工作区,而不是有效的最终的解决方案。
其思路是,当您想要备份一个文件或整个文件夹时,您需要打包并存储全部可能存在的信息。因此,当需要尝试枚举文件中的流时,BackupRead() 是您最好的朋友。我将重点介绍该函数的原型:
BOOL BackupRead(
HANDLE hFile,
LPBYTE lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
BOOL bAbort,
BOOL bProcessSecurity,
LPVOID *lpContext
);
为了我们的目的,您此处可忽略诸如上下文和安全等方面。
hFile 参数必须通过调用
CreateFile() 获得,而
lpBuffer 应指向
WIN32_STREAM_ID 数据结构:
typedef struct _WIN32_STREAM_ID {
DWORD dwStreamId;
DWORD dwStreamAttributes;
LARGE_INTEGER Size;
DWORD dwStreamNameSize;
WCHAR cStreamName[ANYSIZE_ARRAY];
} WIN32_STREAM_ID, *LPWIN32_STREAM_ID;
这种结构的前 20 个字节表示每个流的标题。流的名称紧随
dwStreamNameSize 字段后面出现,名称后面跟着流的内容。因为传统的文件内容可被视为流 — 尽管是未命名的流,所以要想枚举所有的流,您只需进行循环,直到
BackupRead 返回 False。实际上,
BackupRead 应该能读取所有与给定的文件或文件夹相关的信息:
WIN32_STREAM_ID sid;
ZeroMemory(&sid, sizeof(WIN32_STREAM_ID));
DWORD dwStreamHeaderSize = (LPBYTE)&sid.cStreamName -
(LPBYTE)&sid+ sid.dwStreamNameSize;
bContinue = BackupRead(hfile, (LPBYTE) &sid,
dwStreamHeaderSize, &dwRead, FALSE, FALSE,
&lpContext);
上面的这个小段是在流的标题中读到的关键代码。如果该操作是成功的,即可尝试读取该流的实际名称:
WCHAR wszStreamName[MAX_PATH];
BackupRead(hfile, (LPBYTE) wszStreamName, sid.dwStreamNameSize,
&dwRead, FALSE, FALSE, &lpContext);
在访问下一个流之前,首先要调用
BackupSeek(),向前移动备份指示器:
BackupSeek(hfile, sid.Size.LowPart, sid.Size.HighPart,
&dw1, &dw2, &lpContext);
在多数情况下,您可将流视为常规文件 — 如,要删除流,可以用
DeleteFile()。如果想要刷新流的内容,只需使用
ReadFile() 和
WriteFile()。没有正式的和得到支持的方法来移动或重新命名流。在本文的最后部分,我将利用本代码建立一个 NTFS 2000 专用的 Windows shell 扩展,将新的属性页添加到所有带流信息的文件中。
Borland CPP Builder
C++ Bulder Developer's Journal
Borland Delphi
Borland Global Community
Borland Newsgroup
delphi and c++ builder tools directory
delphi information magazine
delphi3000.com - delphi community for knowledge exchange
Programmer深度论坛
Torry's Delphi pages
大富翁论坛
C
Bjarne Stroustrup's Homepage
C-C++ Users Journal Web Site
Microsoft Visual Studio
Visual C++开发指南网站首页
MSDN中国开发中心
Others
李开复的中国学生网站
曾子源码软件下载站
SecurityFocus
SourceForge
CodeProject
SearchTech
P&D
C++,C#,设计模式...
CodeGuru
Microsoft TechNet 主页
MSDN 中文网站
Regular Expression Library
SUN技术社区
Stream Media
流媒体.Liumeiti.com
MPEG Industry Forum
W3C Synchronized Multimedia Home page
中国视频在线
搜新网 流媒体技术网站 www.souxin.com
Tcl/Tk
[incr Tcl] home page
Tcl Developer site
Tcl-Tk中文网
UNIX/LINUX
China Linux Forum
ChinaUnix.net--中国最大的Unix技术社区--Linux-Unix爱好者的网上家园
Tech. Blog
Bjarne Stroustrup
Paul Gustavson
Peter Norvig
在VC中输入Tchar麻烦,所以写了个宏方便使用。
// VS2005
Sub ChangeToTChar()
'DESCRIPTION: Change Normal String to T Char String, TChar String to Normal String.
Dim doc
doc = ActiveDocument
' Be sure active document is a text document
If doc Is Nothing Then
Exit Sub
ElseIf doc.Type <> "Text" Then
Exit Sub
End If
Dim CurrText
Dim CurrTextLen
CurrText = doc.Selection.Text
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If CurrTextLen = 0 Then
CurrText = " TEXT(""" & CurrText & """)"
doc.Selection.Text = CurrText
doc.Selection.CharLeft(2)
Else
If Mid(CurrText, 1, 1) = """" Then
'MsgBox Mid(CurrText,CurrTextLen,1)
If Mid(CurrText, CurrTextLen, 1) = """" Then
CurrText = " TEXT(" & CurrText & ") "
Else
Exit Sub
End If
ElseIf Mid(CurrText, 1, 2) = "_T" Then
CurrText = Mid(CurrText, 3, CurrTextLen - 2)
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If Mid(CurrText, 1, 1) = "(" And Mid(CurrText, CurrTextLen, 1) = ")" Then
CurrText = Mid(CurrText, 2, CurrTextLen - 2)
Else
Exit Sub
End If
ElseIf Mid(CurrText, 1, 4) = "TEXT" Then
CurrText = Mid(CurrText, 5, CurrTextLen - 4)
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If Mid(CurrText, 1, 1) = "(" And Mid(CurrText, CurrTextLen, 1) = ")" Then
CurrText = Mid(CurrText, 2, CurrTextLen - 2)
Else
Exit Sub
End If
Else
'Here Are Not String
'CurrText = " _T(""" & CurrText & """) "
Exit Sub
End If
doc.Selection.Text = CurrText
End If
End Sub
// VS2003
Sub ChangeToTChar()
'DESCRIPTION: Change Normal String to T Char String, TChar String to Normal String.
Dim doc
Set doc = ActiveDocument
' Be sure active document is a text document
If doc Is Nothing Then
Exit Sub
Elseif doc.Type <> "Text" Then
Exit Sub
End If
Dim CurrText
Dim CurrTextLen
Set CurrText = doc.Selection
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If CurrTextLen = 0 Then
CurrText = " TEXT(""" & CurrText & """)"
doc.Selection = CurrText
doc.Selection.CharLeft dsMove, 2
Else
If Mid(CurrText,1,1) = """" Then
'MsgBox Mid(CurrText,CurrTextLen,1)
If Mid(CurrText,CurrTextLen,1) = """" Then
CurrText = " TEXT(" & CurrText & ") "
Else
Exit Sub
End If
ElseIf Mid(CurrText,1,2) = "_T" Then
CurrText = Mid(CurrText,3,CurrTextLen-2)
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If Mid(CurrText,1,1) = "(" and Mid(CurrText,CurrTextLen,1) = ")" Then
CurrText = Mid(CurrText,2,CurrTextLen-2)
Else
Exit Sub
End If
ElseIf Mid(CurrText,1,4) = "TEXT" Then
CurrText = Mid(CurrText,5,CurrTextLen-4)
CurrText = Trim(CurrText)
CurrTextLen = Len(CurrText)
If Mid(CurrText,1,1) = "(" and Mid(CurrText,CurrTextLen,1) = ")" Then
CurrText = Mid(CurrText,2,CurrTextLen-2)
Else
Exit Sub
End If
Else
'Here Are Not String
'CurrText = " _T(""" & CurrText & """) "
Exit Sub
End If
doc.Selection = CurrText
End If
End Sub