- 浏览: 9892 次
最新评论
VC 小技巧(一)
2010年06月26日
1.修改主窗口风格
AppWizard 生成的应用程序框架的主窗口具有缺省的窗口风格,比如在窗口标题条中自动添加文档名、窗口是叠加型的、可改变窗口大小等。要修改窗口的缺省风格,需要重载CWnd::PreCreateWindow (CREATESTRUCT& cs )函数,并在其中修改CREATESTRUCT 型参数cs 。
CWnd::PreCreateWindow 函数先于窗口创建函数执行。如果该函数被重载,则窗口创建函数将使用CWnd::PreCreateWindow 函数返回的CREATESTRUCT cs 参数所定义的窗口风格来创建窗口;否则使用预定义的窗口风格。
CREATESTRUCT 结构定义了创建函数创建窗口所用的初始参数,其定义如下:
typedef struct tagCREATESTRUCT {
LPVOID lpCreateParams; // 创建窗口的基本参数
HANDLE hInstance; // 拥有将创建的窗口的模块实例句柄
HMENU hMenu; // 新窗口的菜单句柄
HWND hwndParent; // 新窗口的父窗口句柄
int cy; // 新窗口的高度
int cx; // 新窗口的宽度
int y; // 新窗口的左上角Y 坐标
int x; // 新窗口的左上角X 坐标
LONG style; // 新窗口的风格
LPCSTR lpszName; // 新窗口的名称
LPCSTR lpszClass; // 新窗口的窗口类名
DWORD dwExStyle; // 新窗口的扩展参数
} CREATESTRUCT;
CREATESTRUCT 结构的style 域定义了窗口的风格。比如,缺省的MDI 主窗口的风格中就包括FWS_ADDTOTITLE (在标题条中显示当前的工作文档名)、FWS_PREFIXTITLE (把文档名放在程序标题的前面)、WS_THICKFRAME (窗口具有可缩放的边框)等风格。由于多种风格参数由逻辑或("|")组合在一起的,因此添加某种风格,就只需用"|"把对应的参数加到CREATESTRUCT 结构的style 域中;删除已有的风格,则需用"&"连接CREATESTRUCT 结构的style 域与该风格的逻辑非值。
CREATESTRUCT 结构的x 、y 、cx 、cy 域分别定义了窗口的初始位置和大小,因此,在CWnd::PreCreateWindow 函数中给它们赋值,将能定义窗口的初始显示位置和大小。
下例中的代码将主框窗口的大小将固定为1/4 屏幕,标题条中仅显示窗口名,不显示文档名。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
// 修改主窗风格
cs.style &= ~FWS_ADDTOTITLE; // 去除标题条中的文档名
cs.style &= ~WS_THICKFRAME; // 去除可改变大小的边框
cs.style |= WS_DLGFRAME; // 增加不能改变大小的边框
// 确定主窗的大小和初始位置
int cxScreen = ::GetSystemMetrics(SM_CXSCREEN);// 获得屏幕宽
int cyScreen = ::GetSystemMetrics(SM_CYSCREEN); // 获得屏幕高
cs.x = 0; // 主窗位于左上角
cs.y = 0;
cs.cx = cxScreen/2; // 主窗宽为1/2 屏幕宽
cs.cy = cxScreen/2; // 主窗高为1/2 屏幕高
return CMDIFrameWnd::PreCreateWindow(cs);
}
2. 窗口的分割与停靠
一、新建一个类CMySplitter, 基类为CSplitterWnd
二、重载该类的OnMouseMove 函数:
void CMySplitter::
OnMouseMove(UINT nFlags, CPoint point)
{
// 限制切分条的运动范围。
if(point.x600)
{
CWnd:: OnMouseMove(nFlags, point);
}
else
{
CSplitterWnd:: OnMouseMove(nFlags, point);
}
}
三、 然后就可以跟一般的窗口分割那样去做了,if(point.x600) 这里的范围可以随你去设置了 ^_^ ,够简单吧。
四、切分窗口
在MaiFram.h 建立切分条对象:
protected:
CMySplitter m_wndSplitter; // 切分窗口对象
// 在MaiFram.cpp 中实现窗口切分:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,CCreateContext* pContext) { // 创建拆分器窗口
if (!m_wndSplitter.CreateStatic(this, 1, 2))
return FALSE;
if
(!m_wndSplitter.CreateView(0, 0,
RUNTIME_CLASS(CLeftView),CSize(228,100), pContext)
||!m_wndSplitter.CreateView(0,1, RUNTIME_CLASS(CDataEditView), CSize(100, 100), pContext))
{
m_wndSplitter.DestroyWindow();
return FALSE;
}
return TRUE;
}
3. 如何使我的程序在启动时不创建一个新文档
[ 问题]
如何使我的程序在启动时不创建一个新文档?
[ 解答]
在程序的InitInstance 中的ProcessShellCommand 函数之前加入: cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
4. 初始化应用程序的大小
如果想使应用程序界面(文档)在开始运行是按你的尺寸展现在屏幕上,
添加代码如下:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
int xsize=::GetSystemMetrics(SM_CXSCREEN);
int ysize=::GetSystemMetrics(SM_CYSCREEN);
cs.cx=xsize*5/10;
cs.cy=ysize*5/10;
cs.x=(xsize-cs.cx)/2;
cs.y=(ysize-cs.cy)/2;
}
其中的5/10 是你的初始界面占屏幕的百分比,可以自己修改。如果想使应用程序大小固定添加cs.style&=~WS_THICKFRAME;
5. 如何全屏显示( 没有标题, 没有菜单, 没有工具条)
[ 解决方法]
重载CMainFrame 的ActivateFrame 函数:
void CMainFrame::ActivateFrame(int nCmdShow)
{
CRect cRectdesktop;
WINDOWPLACEMENT windowplacement;
::GetWindowRect(::GetDesktopWindow(),&cRectdesktop );
::AdjustWindowRectEx(&cRectdesktop,GetStyle(),TRUE ,GetExStyle());
windowplacement.rcNormalPosition=cRectdesktop;
windowplacement.showCmd=SW_SHOWNORMAL;
SetWindowPlacement(&windowplacement);
CFrameWnd::ActivateFrame(nCmdShow);
}
6. 如何限制mdi 子框架最大化时的大小
用ptMaxTrackSize 代替prMaxSize, 如下所示:
void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// TOD Add your message handler code here and/or call default
CChildFrame::OnGetMinMaxInfo(lpMMI);
lpMMI->ptMaxTrackSize.x = 300;
lpMMI->ptMaxTrackSize.y = 400;
}
7. 程序如何删除自己
/////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {
// Is this the Original EXE or the clone EXE?
// If the command-line 1 argument, this is the Original EXE
// If the command-line >1 argument, this is the clone EXE
if (__argc == 1) { // Original EXE: Spawn clone EXE to delete this EXE // Copy this EXEcutable image into the user''s temp directory TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH]; GetModuleFileName(NULL, szPathOrig, _MAX_PATH); GetTempPath(_MAX_PATH, szPathClone); GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone); CopyFile(szPathOrig, szPathClone, FALSE); //*** 注意了***:
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTI
NG, FILE_FLAG_DELETE_ON_CLOSE, NULL);
// Spawn the clone EXE passing it our EXE''s process handle
// and the full path name to the Original EXE file.
TCHAR szCmdLine[512];
HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());
wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, hProcessOrig, szPat
hOrig);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(hProcessOrig);
CloseHandle(hfile);
// This original process can now terminate.
} else {
// Clone EXE: When original EXE terminates, delete it
HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
WaitForSingleObject(hProcessOrig, INFINITE);
CloseHandle(hProcessOrig);
DeleteFile(__targv[2]);
// Insert code here to remove the subdirectory too (if desired).
// The system will delete the clone EXE automatically
// because it was opened with FILE_FLAG_DELETE_ON_CLOSE
}
return(0);
}
-------------------------------------------------- -------------
这一段程序思路很简单:不是不能在运行时直接删除本身吗?好,那么程序先复制(CLONE )一个自己,用复制品起动另一个进程,然后自己结束运行,则原来的EXE 文件不被系统保护. 这时由新进程作为杀手删除原来的EXE 文件,并且继续完成程序其他的功能。
新进程在运行结束后,复制品被自动删除。这又是值得介绍的一个把戏了,注意:
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,OPEN_EXISTIN
G, FILE_FLAG_DELETE_ON_CLOSE, NULL);
这里面的FILE_FLAG_DELETE_ON_CLOSE 标志, 这个标志是告诉操作系统,当和这个文件相关的所有句柄都被关闭之后( 包括上面这个
CREATEFILE 创建的句炳) ,就把这个文件删除。几乎所有的临时文件在创建时,都指明了这个标志。另外要注意的是: 在复制品进程对原始程序操刀之
前, 应该等待原进程退出. 在这里用的是进程同步技术. 用HANDLE hProcessOrig =
OpenProcess(SYNCHRONIZE,
TRUE,GetCurrentProcessId()); 得到原进程句柄.SYNCHRONICE 标志在NT 下有效, 作用是使OpenProcess 得
到的句柄可以做为同步对象. 复制品进程用WaitForSingleObject 函数进行同步, 然后一个DeleteFile, 以及进行其它销毁证据(比
如删目录)的工作, 一切就完事了。
程序是基于CONSOLE 的,通过传入的参数确定是原始的进程还是复制品新进程,并且得到需要操
作的目标文件的信息(主要是路径),复制品放在系统的TEMP 目录(GetTempPath 得到),你也可以随便找个你认为安全的地方(比如:
WINDOWS\SYSTEM32 等等)。这里面没有甚么深的技术. 再看其他的一些实现删除自己的例子, 比如说在进程退出前, 用fwrite 等方法输出一
个.BAT 文件, 在里面写几句DEL, 然后WINEXEC 一下这个BAT 文件即可. 玩儿过DOS 的虫虫大多都会。
8. 如何实现SDI 与MDI 的转换
我想将一个编好的SDI 应用程序转换为MDI ,很明显要有多处的改变。
你可以这样做:建立一个继承于CMDIChidWnd 的类,不防设为CChldFrm. 在CWinApp 中作如下变化。
InitInstance()
{
. ...
//instead of adding CSingleDocTemplate
// Add CMultiDocTemplate.
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSDIDoc),
RUNTIME_CLASS(CChldFrm),
// For Main MDI Frame change this frame window from // CFrameWnd derivative ( i.e. CMainFrame ) // to your CMDIChildWnd derived CChldFrm. RUNTIME_CLASS(CSDIView)); /// After this it is required to create the main frame window // which will contain all the child windows. Now this window is // what was initially frame window for SDI. CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; ..... } 在从CMDIFrameWnd 中继承的类CMainFrame 代替CFramWnd 后,所有的类都将从CMDIFrame 继承,而不是CFrameWnd, 编译运行后你就会发现程序已经从SDI 变换到MDI 。
注意:在CMainFram 中必须将构造函数从private 改为public. 否则会出错。
9. 想在程序一启动时就自动关闭窗口, 不在任务栏里显示
用CTRL+W 打开ClassWizard;
点击Class Info 页, 类名是工程名Dlg,
再在左下方的"Filter" 中选择"Windows";
回到Message Maps 页, 就可以看到消息中有WM_WINDOWPOSCHANGING,
加入代码, 如上所示.
这样运行*.EXE, 不但看不到主界面, 任务栏也没有, 就是任务管理器中的" 应用程序" 中也不列出, 那该如何关闭它?
在任务管理器的" 进程" 中可以找到它, 这是黑客程序常用的方法.
如果需要的话, 连" 进程" 中也看不到. 这样要终止它就是问题了
10. 如何修改frame 窗口的背景颜色
MDI 窗口的客户区是由frame 窗口拥有的另一个窗口覆盖的。为了改变frame 窗口背景的颜色,只需要这个客户区的背景颜色就可以了。你必须自己处理WM_ERASEBKND 消息。下面是工作步骤:
创建一个从CWnd 类继承的类,就叫它CMDIClient 吧;
在CMDIFrameWnd 中加入CMDIClient 变量;(具体情况看下面的代码)
#include "MDIClient.h"
class CMainFrame : public CMDIFrameWnd
{
...
protected:
CMDIClient m_wndMDIClient;
}
重载CMDIFrameWnd::OnCreateClient ,下面是这段代码,请注意其中的SubclassWindow() ;
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) )
{
m_wndMDIClient.SubclassWindow(m_hWndMDIClient);
return TRUE;
}
else
return FALSE;
}
最后要在CMDIClient 中加入处理WM_ERASEBKGND 的函数。
11. 在MFC 下实现图像放大镜
一、 引言
当我们想仔细观察某个细微的东西时,一般都会使用放大镜。而要看清显示在计算机屏幕上的图片或文字时通常也
可以借助于Windows 操作系统附带的放大程序来实现。但该程序只能以固定的放大倍数
去进行观看,有时并不能满足我们的需要。本文就通过MFC 基本类库提供的StretchBlt 函数来实现对屏幕图象的局部放大,并且可以随意放大、缩小,
选取到合适的放大倍数来对图像的细节进行观察。
二、 设计与实现
本程序主要用来对图像的局部进行可调倍数的放大,应当具有以下主要功能:
1. 移动MOUSE 放大显示图像的不同部位
2. 左击增加放大倍率、右击减少放大倍率。
从光学角度来看,对物体的放大成像是通过把较小的真实物体显示成尺寸较大的虚像来实现的。因此我们可以用类
似的原理,把图像中待放大的区间从较小的显示范围拉伸到一个比较大的显示范围即可达到图
像放大的效果,两个区间的比值也就是图像的放大倍率。可以通过缩小源区间的范围或扩大放大区间的范围来实现放大倍率的调整。在MFC 基本类库中提供有
CDC 类的StretchBlt 函数可以将一幅位图从一个源矩形以一定的光栅操作拷贝到另外一个不同大小的目标矩形中去,因此可以用此函数来实现图象放大
的功能,其函数原形声明如下:
BOOL StretchBlt( int x, int y, // 目标矩形的坐标原点
int nWidth, int nHeight, // 目标矩形的长度和宽度
CDC* pSrcDC, // 源设备环境句柄
int xSrc, int ySrc, // 源矩形的坐标原点
int nSrcWidth, int nSrcHeight, // 源矩形的长度和宽度
DWORD dwRop ); // 光栅操作标志
当指定的源和目标矩形的宽度或高度不一样时,StretchBlt 函数将创建一个位图的镜像。如果是宽度有变化,就沿x 轴创建镜像;如果是高度上有变化就沿y 轴创建镜像。而且该函数可以在内存中对源图象做拉伸或压缩处理后再拷贝到目标矩形中去。
要放大图像首先要把图像显示出来,一般可以从文件动态装载或者直接从资源中用LoadBitMap 读取位图资源。下面的代码放在视类的OnDraw 函数中,用以在第一次调用时将位图装载并显示出来,以后再被调用只是负责重画:
……
static bool load;
if (!load)
{ BITMAP bm; load = !load; // 装载位图到 m_pBitmap
m_pBitmap->LoadBitmap(IDB_BITMAP1);
// 创建相关的设备环境
m_pdcMem->CreateCompatibleDC(pDC);
// 将位图从m_ pBitmap 中装载到m_pdcMem 中
m_pdcMem->SelectObject(m_pBitmap);
m_pBitmap->GetObject(sizeof(bm),&bm);
m_sizeSource.cx = bm.bmWidth;
m_sizeSource.cy = bm.bmHeight;
m_sizeDest = m_sizeSource;
// 把位图从m_pdcMem 中装载到当前正在使用的设备环境中
pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy ,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana) ;
}
else
{
// 重画图像
pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy ,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana) ;
SetCursor(NULL);// 隐藏鼠标
}
要实现前面提到的第一个功能:移动MOUSE 放大显示图像的不同部位,显然首先要在
WM_MOUSEMOVE 消息的响应函数里编写代码。以整形变量s 和d 来分别表示所选取的源和目标区域的大小,再通过消息响应函数OnMouseMove
的入口参数point 来确定当前的鼠标位置就可以计算出我们要选取的源和目标区域在图像的位置。放大的工作只需通过StretchBlt 函数将源区域中所
在的图像拉伸到目标矩形那么大,并拷贝给目标区域即可实现所选区域的放大效果,下面是部分主要代码:
……
// 确定目标区域、源区域的坐标位置
CRect srect,drect,mrect;
srect.left = point.x - s;
srect.top = point.y - s;
srect.right = point.x + s;
srect.bottom = point.y + s;
drect.left = point.x - d;
drect.top = point.y - d;
drect.right = point.x + d;
drect.bottom = point.y + d;
mrect.left = oldx - d;
mrect.top = oldy - d;
mrect.right = oldx + d;
mrect.bottom = oldy + d;
dd = 2*d;
// 获取可用设备环境句柄
CDC * pDC = GetDC();
OnPrepareDC(pDC);
if (recover)
{
pDC->BitBlt(mrect.left,mrect.top,dd,dd,m_pdcMem,mre ct.left,mrect.top,mana);
}
// 隐藏鼠标
SetCursor(NULL);
// 拉伸放大
pDC->StretchBlt(drect.left,drect.top,drect.Width(), drect.Height(),m_pdcMem,srect.left,srect.top,srect. Width(),srect.Height(),SRCCOPY);
// 保存当前鼠标位置备用
oldx = point.x; oldy = point.y;
// 释放设备环境句柄
ReleaseDC(pDC);
recover = true;
……
为了实现第二个功能:左击增加放大倍率、右击减少放大倍率,可以分别在消息
WM_LBUTTONDOWN 和消息WM_RBUTTONDOWN 中添加改变选取区域大小的代码来实现。如果选取源矩形不变而改变目标矩形的大小会随着放
大倍数的增大,显示区域也不断增大,当放大到一定程度的时候会另人无法忍受,因此选取通过缩放源矩形大小来控制放大倍数的方案:
void CZoomInView::OnRButtonDown(UINT nFlags, CPoint point)
{ if (s 5) { s-=3; SetCursor(NULL); OnMouseMove(nFlags, point); } CView::OnLButtonDown(nFlags, point); } (完)
发表评论
-
socket阻塞和非阻塞的区别
2012-01-20 00:40 677socket阻塞和非阻塞的区 ... -
Socket编程基础
2012-01-20 00:40 672Socket编程基础 2010年10月20日 TCP/I ... -
MTK 上的socket
2012-01-20 00:40 776MTK 上的socket 2010年10月0 ... -
VxWorks下编程的几个误区
2012-01-20 00:40 596VxWorks下编程的几个误区 ... -
WMI(Windows管理规范)常见问题解答
2012-01-17 00:58 498WMI(Windows管理规范)常见 ... -
网络和黑客windows编程
2012-01-17 00:58 784网络和黑客windows编程 2011年04月18日 第 ... -
Windows XP的小秘密 {7}
2012-01-17 00:57 720Windows XP的小秘密 {7} 201 ... -
转: Boost下载安装编译配置使用指南(含Windows和Linux)
2012-01-17 00:57 642转: Boost下载安装编译配 ... -
通过QQ旋风离线下载Android SDK,速度超快
2012-01-17 00:57 956通过QQ旋风离线下载Android SDK,速度超快 201 ... -
EGLIBC库介绍
2012-01-15 19:41 517EGLIBC库介绍 2011年05月05 ... -
c库函数qsort使用方法实例
2012-01-15 19:41 549c库函数qsort使用方法实例 2010年01月03日 ... -
制作和使用自定义C库文件
2012-01-15 19:41 618制作和使用自定义C库文 ... -
九标海外项目负责人爬进!
2012-01-15 19:41 650九标海外项目负责人爬 ... -
[转]GCC笔记
2012-01-15 19:41 582[转]GCC笔记 2010年03月23日 The His ...
相关推荐
vc使用小技巧
VC小技巧20个,VC小技巧20个,VC小技巧20个,VC小技巧20个
VC小技巧收集 VC小技巧收集 VC小技巧收集 VC小技巧收集 VC小技巧收集
VC的若干实用小技巧,借助于一些调试等的小技巧,可以让你轻松的完成VC的工作。
VC常用小技巧
vc 编写小技巧
。。。。。。。。。VC小技巧20个 。。。。。。 还不错的可以借鉴一下的。这个最适合初学者了,希望可以给你们带来点帮助。
108条vc实用小技巧知识,非常有用!
20个VC开发小技巧20个VC开发小技巧20个VC开发小技巧20个VC开发小技巧
VC常用小知识,比如如何通过代码获得应用程序主窗口的 指针? 确定应用程序的路径,如何在程序中获得其他程序的 图标? 等等
VC若干小技巧
关于vc的几个编程小技巧。 主要涵盖vc编程中,经常遇到的问题,提供解决方法
此包中有:VC实现透明背景和半透明图片.txt vc jpg 背景图.txt 怎么设置鼠标光标成为一个指定的 _ani形状以及使用vc编写小程序的一些技巧给大家分享,希望对大家有所帮助等资料
积累的VC编程小技巧 rar压的 word文档 95页 全面的vc++小技巧集合,感谢原作者
总结了在VC开发过程常用的一些知识点和技巧。这些小技巧简单实用,希望后来者少走些弯路。
VC小技巧是在学习VC过程中积累起的一些经验,非常适合喜欢并热爱VC编程的人员。
VC编程小技巧20个---最好放到word中看看吧
使用vc6.0的一些很实用的小技巧。如: 1.检测程序中的括号是否匹配 2.查看一个宏(或变量、函数)的宏定义
很实用的VC++开发小技巧,汇集众多常见的问题的VC开发技巧
VC编程小技巧20个