VC开发以及外挂制作总结.docx
《VC开发以及外挂制作总结.docx》由会员分享,可在线阅读,更多相关《VC开发以及外挂制作总结.docx(24页珍藏版)》请在冰豆网上搜索。
VC开发以及外挂制作总结
1.注册dll
regsvr32JpgShowCtl.ocx
2.如果调用了AfxInitOle,那么就不用调用CoInitialize
因为AfxInitOle已经调用过了
而调用CoInitialize需要最后时候调用CoUnInitialize
与AfxOleInit()对应的是,AfxOleTerm()。
AfxOleInit()和AfxOleTerm()其实也是需要成对的,但是,在你的程序中,AfxOleTerm()可以不出现,这是因为,MFC已经帮你做好了(有兴趣的话,你可以仔细研究一下CWinThread:
:
m_lpfnOleTermOrFreeLib,而CWinApp是从CWinThread继承的)。
3.HWNDoldHWnd=NULL;
EnumWindows(EnumWndProc,(LPARAM)&oldHWnd);//枚举所有运行的窗口
if(oldHWnd!
=NULL)
{
:
:
ShowWindow(oldHWnd,SW_SHOWMAXIMIZED);//激活找到的前一个程序
:
:
SetForegroundWindow(oldHWnd);//把它设为前景窗口
returnFALSE;//退出本次运行
}
CStringg_szPropName="GPSWEBVER";
HANDLEg_hValue=(HANDLE)1;
4.添加一个枚举窗口的函数
BOOLCALLBACKEnumWndProc(HWNDhwnd,LPARAMlParam)
{
HANDLEh=GetProp(hwnd,g_szPropName);
if(h==g_hValue)
{
*(HWND*)lParam=hwnd;
returnfalse;
}
returntrue;
}
GetVersionEx
在一个OSVERSIONINFO结构中载入与平台和操作系统有关的版本信息
5.关于htmlView使用心得
首先定义一个子类例如CHtmlCtrl继承CHtmlView
然后实现虚函数Create
这个Create需要实现以下代码
m_pCreateContext=pContext;
if(!
CView:
:
Create(lpszClassName,lpszWindowName,
dwStyle,rect,pParentWnd,nID,pContext))
{
returnFALSE;
}
RECTrectClient;
GetClientRect(&rectClient);
//createthecontrolwindow
//AFX_IDW_PANE_FIRSTisasafebutarbitraryID
if(!
m_wndBrowser.CreateControl(CLSID_WebBrowser,lpszWindowName,
WS_VISIBLE|WS_CHILD,rectClient,this,AFX_IDW_PANE_FIRST))
{
DestroyWindow();
returnFALSE;
}
LPUNKNOWNlpUnk=m_wndBrowser.GetControlUnknown();
HRESULThr=lpUnk->QueryInterface(IID_IWebBrowser2,(void**)&m_pBrowserApp);
if(!
SUCCEEDED(hr))
{
m_pBrowserApp=NULL;
m_wndBrowser.DestroyWindow();
DestroyWindow();
returnFALSE;
}
returnTRUE;
这样就可以通过IDispatch接口响应到网页的一些事件,包括点击移动以及js事件。
6.
用CreateDC,getDC等建立了DC后,在不再使用时应该用
ReleaseDC释放他们所建立的DC,而用CreateCompatibleDC建立的DC应该用DeleteDC释放
7.CBitmapHBITMAP相互转化
CBitmap*pBitmap=newCBitmap
这个时候只有CBitmap的空间,但是没有图像
需要pBitmap->Attach(hBitmap)
来获得图像
而CDC获取图像的方式是CDC.SelectObject(hNewBitmap)
同时返回里面的hOldBitmap
pBitmap使用完以后需要DeleteObject
这样就释放掉与其相关的资源,而且可以Attach新的资源。
而deletepBitmap则不会释放资源,只会讲自己CBitmap对象释放掉。
8.回调函数的使用
一般来说回调函数的应用的一种情况
voidfun1()
{
许多代码1
logic1();
许多代码2
}
voidfun2()
{
许多代码1
logic2()
许多代码2
}
fun1和fun2功能上基本一致,但是有很少部分逻辑有点区别。
而许多代码2和许多代码1不大容易变成函数。
这个时候就需要根据外面的调用把logic1和logic2当做参数传进来,在适当的时候调用
fun(logicfun&logic)
{
许多代码1
logic
许多代码2
}
这样就把函数内部的逻辑变到了参数上面去。
9.Invalidate()--RedrawWindow()--UpdateWindow()三个函数有什么异同?
Invalidate()是强制系统进行重画,但是不一定就马上进行重画。
因为Invalidate()只是通知系统,此时的窗口已经变为无效。
强制系统调用WM_PAINT,而这个消息只是Post就是将该消息放入消息队列。
当执行到WM_PAINT消息时才会对敞口进行重绘。
UpdateWindow只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT。
RedrawWindow()则是具有Invalidate()和UpdateWindow()的双特性。
声明窗口的状态为无效,并立即更新窗口,立即调用WM_PAINT消息处理。
//
CArray
10.
在使用一个数组之前,先用SetSize函数建立数组的大小,并为数组分配内存。
如果应用程序没有使用SetSize函数,则向数组中增加元素会使它被频繁地再分配和拷贝。
频繁再分配和拷贝的效率很低,并且可能使内存变得很零碎。
指针数组不能被串行化。
当一个指针数组被删除时,或当其元素被删掉时,只删掉指针,而这些指针所引用的实体不被删除。
11.下载文件时候的动画
HWNDm_hAnimationCtrl;
HINSTANCEm_hInstance,m_avi;
//TODO:
Addextrainitializationhere
if((m_avi=LoadLibrary("Shell32.dll"))==NULL)
{
MessageBox("Unabletoloadlibrary.","ANI",0);
}
else
{
//Libraryloadednowcreatetheanimationcontrol
m_hAnimationCtrl=CreateWindowEx(0,//Style
ANIMATE_CLASS,//ClassName
NULL,//Windowname
WS_CHILD|WS_VISIBLE|//WindowStyle
ACS_TRANSPARENT|ACS_CENTER,
0,//Left
0,//Top
360,//Right
60,//Bottom
m_hWnd,//Handleofparent
NULL,//Menu
m_avi,//hInstance
NULL);//Userdefinedstyle
//ControlcreatedNowopentheaviresource
if(:
:
SendMessage(m_hAnimationCtrl,ACM_OPEN,(WPARAM)m_avi,(LPARAM)161)==NULL)
MessageBox("CannotLoadtheaviresource","ANI",0);
//play
:
:
SendMessage(m_hAnimationCtrl,ACM_PLAY,(WPARAM)-1,MAKELONG(0,-1));
//STOP
:
:
SendMessage(m_hAnimationCtrl,ACM_STOP,(WPARAM)-1,MAKELONG(0,-1));
//获取按钮,给按钮发送消息
CWnd*pButton1=GetDlgItem(IDC_BUTTON1);
if(pButton1)
{
:
:
SendMessage(pButton1->m_hWnd,BM_CLICK,0,0);
}
给菜单项发送消息
:
:
SendMessage(AfxGetMains");GetSafeHwnd(),WM_COMMAND,ID_TEST1,NULL);
设置状态栏第一个地方的文字
m_wndStatusBar.SetPaneText(0,"helloworld");
12.在MainFrame框架下有个消息循环,底层的实现是这样的。
Becausethereturnvaluecanbenonzero,zero,or-1,avoidcodelikethis:
while(GetMessage(lpMsg,hWnd,0,0))...
Thepossibilityofa-1returnvaluemeansthatsuchcodecanleadtofatalapplicationerrors.Instead,usecodelikethis:
BOOLbRet;
while((bRet=GetMessage(&msg,hWnd,0,0))!
=0)
{
if(bRet==-1)
{
//handletheerrorandpossiblyexit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Anapplicationtypicallyusesthereturnvaluetodeterminewhethertoendthemainmessageloopandexittheprogram.
如果点击菜单或者按钮就会有消息进入这个消息循环,从而被DispatchMessage分发到相应的处理过程去处理。
如果发送WM_QUIT消息,就会返回-1,从而整个驱动的核心被停止。
但是如果你在一个消息处理的事件中加入循环,那么系统就不会再响应其他消息,直到你的循环结束。
如果你想让系统响应其他消息,那么你的循环事件必须做成多线程程序。
多线程MFC下有两种方式一个是工作者线程一个是用户界面线程。
工作者线程不会响应消息,一般是做后台工作。
用户界面线程可以响应消息。
13.如何等待线程退出,然后主线程再退出
比如主线程有10个子线程,
当主线程退出前要等待子线程退出。
但是这个时候子线程可能在完成一些工作,比如写文件等,如果强行中止会影响结果。
一个方式是
循环等待所有线程退出
WaitForSingleObject(Thread[i]->m_hThread,TIMEOUT);//这里可以考虑使用
INFINITE
GetExitCodeThread(Thread[i]->m_hThread,&dwExitCode);
if(dwExitCode==STILL_ACTIVE)
{
TerminateThread(Thread[i]->m_hThread,dwExitCode);
}
如果退出码不对,那么需要强制退出。
也可以把句柄放到数组里面,同时等待退出
WaitForMultipleObjects(10,handle,TRUE,10000);
14.比如带界面的程序最小化,能够把堆中分配的内存释放掉。
15.Warning:
constructingCOleException,scode=DISP_E_MEMBERNOTFOUND($80020003).
发现这个错误一般都是继承htmlView的时候OnSize没有处理好
voidCGpsSCView:
:
OnSize(UINTnType,intcx,intcy)
{
CHtmlView:
:
OnSize(nType,cx,cy);
if(:
:
IsWindow(m_hWnd))
{
CRectrect;GetClientRect(rect);//就这一句与CHtmlView的不同
:
:
AdjustWindowRectEx(rect,GetStyle(),FALSE,WS_EX_CLIENTEDGE);
SetWindowPos(NULL,rect.left,rect.top,rect.Width(),rect.Height(),SWP_NOACTIVATE|SWP_NOZORDER);
}
}
16.如果使用MFC扩展库来做dll,如果在dll中需要使用dll的资源,那么如果就需要使用
GetModuleHandle("**.dll")来获取dll句柄。
如果需要使用主程序的资源,**.dll就替换为空
注意代码中,如果都使用IDB_BITMAP1,需要将主程序的IDB_BITMAP1定义为和dll一样的值。
否则就会载入失败。
17.使用CreateFile来追加文件内容。
m_file=CreateFile("c:
\\test.txt",
GENERIC_WRITE|SYNCHRONIZE,
FILE_SHARE_WRITE|FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
NULL);
SetFilePointer(m_file,0,NULL,FILE_END);
DWORDnCOunt=0;
WriteFile(m_file,"helloworld",strlen("helloworld"),&nCOunt,NULL);
CloseHandle(m_file);
18.
VC6.0设置动态链接库工程生成的lib文件的位置
2011-06-2211:
37
在"Projet"->"Settings..."的"Link"选项卡中
"Outputfilename"中设置dll的输出路径
Projectoptions:
中可以看到刚刚设置生成的DLL路径,
紧跟着就是LIB文件的路径,默认应该是DEBUG或者release的目录下,
这里需要手动修改LIB路径到你所需要的设置生成相应lib文件的所在路径,下面一句设置是Release模式下路径:
/out:
"../UltrasoundWorkStation/PatientDBManage.dll"
/implib:
"../UltrasoundWorkStation/PatientDBManage.lib"
下面是DEBUG模式下默认路径,这里未作修改。
。
/out:
"Debug/PatientDBManage.dll"
/implib:
"Debug/PatientDBManage.lib"/pdbtype:
sept(多了一个这个)
根据需要修改之即可。
注意:
这里/implib:
"../UltrasoundWorkStation/PatientDBManage.lib"表示LIB生成路径为:
当前DLL工程的上一级目录下的UltrasoundWorkStation文件夹位置下
19.
加载DLL的方法主要有两种:
一种是隐式链接,另外一种是动态加载。
隐式链接会把DLL中所有标志为_declspec(dllexport)的函数都加载,如果有多个DLL加载时,可能会影响到程序执行的效率。
而用动态加载DLL的方式则可以根据需要去加载用到的函数。
动态加载DLL的方法:
1.生成dll过程:
把生成的.DLL文件复制到测试工程DLLTest目录下。
这里假设该.DLL文件为add.dll,主要代码是:
_declspec(dllexport)intadd(intx,inty)
{
returnx+y;
}
2.使用1生成的dll:
在DLLTest工程中添加DllTest.cpp文件.
首先使用LoadLibrary("add.dll")加载add.dll文件:
HMODULEhmod=LoadLibrary("add.dll");
然后定义一个函数指针的类型:
typedefint(*AddAddr)(intx,inty);
注意,这里的参数与返回类型务必与add.dll文件中函数add的声明一样。
接着:
AddAddrAdd=(AddAddr)GetProcAddress(hmod,"add");
如果Add值为空,则获取函数的地址失败!
if(!
Add)
{
printf("获取函数地址失败!
");
return;
}
最后,可以测试一下:
printf("testadd():
1+2=%d",add(1,2));
运行结果一看,会出现“获取函数地址失败!
”。
为什么会这样?
打开命令行,用cd命令到add.dll工程目录的debug目录下,然后使用命令:
dumpbin-exportsadd.dll
则会看到add.dll文件中的add函数的名称为“?
add@@YAHHH@Z”,而不是函数名add,这是C++编译器的命名改编机制。
修改原来的代码:
AddAddrAdd=(AddAddr)GetProcAddress(hmod,"?
add@@YAHHH@Z");
这时运行就成功了。
但如果按这样去动态加载DLL,那每次获取函数地址都要使用dumpbin命令去获取,则会很麻烦。
那怎样可以直接使用add而不是?
add@@YAHHH@Z这个长长的字符串呢,修改add.dll的add函数,在函数前加上extern"C",再编译add.dll文件所在的工程,复制新生成的add.dll覆盖DLLTest工程目录下的add.dll,原来的代码获取函数地址时使用add,结果运行就成功了。
而再使用dumpbin-exportsadd.dll命令,显示add.dll的中的add函数的名称变成了add.
20
一个函数将CPtrList里所有记录读出来:
POSITIONpos=apStr.GetHeadPosition();
while(pos!
=NULL)
{
str=apStr.GetNext(pos);
//这里,你就可以使用str了
}
21.
OpenCV
cvReleaseImage属于cxcore.lib
#pragmacomment(lib,"cxcore.lib")
cvWaitKey
cvShowImage
cvMoveWindow
cvNameWindow
cvLoadImage
都在highgui.lib
22.让console程序不显示控制台
在默认情况下链接器看到/subsystem下是windows选项的时候,它会自动寻找winmain或者wwinmain
但我们强制指定入口地址,这样运行程序的时候默认的console窗口就会隐藏!
上面是在代码中使用#pragma指令来设置,还有一种就是直接在开发环境的
project->setting->link->projectoption中手工改动!
写了这么多,自己都有点感觉乱,没有办法,以前没写过什么文章,所以措辞可能不太好,希望大家见谅。
1:
如果console程序已经写好了,不能改了,也可以。
写一个API程序,不要画窗口,然后用CreateProcess调用写好的console程序,把属性设成SW_HIDE即可。
2:
不能用控制台来写(CONSLOE),要用WINMAIN做入口就可以了,不画窗口,别人就都看不见了.你只用想想办法把你的进程在任务栏里面隐藏住就可以.
3:
如果是console程序,用API函数GetStdHandle()获得控制台程序的窗口句柄,然后在隐藏窗口
4:
//这一句隐藏控制台
#pragmacomment(linker,"/subsystem:
\"windows\"/entry:
\"mainCRTStartup\"")
23.console接收输入,即使console在后台
while
(1){
intkey=cvWaitKey(10);
if(key==27)break;
if(key==-1)continue;
printf("%c",key);
}
24.创建弹出菜单并响应消息
CMenumenu;
menu.CreatePopupMenu();
ClientToScreen(&point);
menu.AppendMenu(MF_STRING,WM_DESTROY,"Exit");
menu.TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);
menu.DestroyMenu();
需要使用ON_COMMAND来响应消息
命令可以在resource.h中定义例如#defineID_ALERTWM_USER+1000
25.通过发消息在Notepad中写字
HWNDm_LocalWnd=:
:
FindWindow("Notepad",NULL);
HWNDm_ChildWnd=:
:
FindWindowEx(m_LocalWnd,NULL,"Edit","");
:
:
PostMessage(m_ChildWnd,WM_CHAR,'A',0);
:
:
PostMessage(m_ChildWnd,W