关于MFC的各种技巧回答

问】如何判定剪贴板中有没有文本数据?
答】
COleDataObject dataObject;
dataObject.AttachClipboard();
if(dataObject.IsDataAvailable(CF_TEXT))
{
.....//有文本数据
}
问】如何得到ComboBox的Edit句柄?
答】CEdit *pEdit = (CEdit*)CComboBox.GetWindow(GW_CHILD)
问】得到当前用户目录,即:C:\Documents and Settings\...
答】SHGetSpecialFolderPath(NULL,(LPTSTR)szPath,CSIDL_PERSONAL,FALSE);
问】状态栏的高度怎样改变?
答】m_wndStatusBar.GetStatusBarCtrl().SetMinHeight(40);
问】动态调整控件大小时需要注意的问题
答】
程序在执行WM_SIZE时,可能控件还没有被程序创建完成,你必须确保你的控件被创建后才能使用MoveWindow,
1,你可以设一个BOOL变量,初值为FALSE,在OnInitDialog的最后将它的值变成TRUE,在WM_SIZE中判断这个变量,只有当它为真时才进行MoveWindow操作。
2,你也可经先用::IsWindow(控件.GetSafeHwnd())判断控件是否创建,只有当它为真时才进行MoveWindow操作。
问】在PreTranslateMessage()中如何取得组合键比如CTRL+F1
答】if(pMsg->message ==WM_KEYDOWN&&pMsg->wParam==VK_F1 &&GetKeyState(VK_CONTROL)&0x80)
问】SendMessage PostMessage的区别
答】
PostMessage发送消息后就不等了,发了就回,管你处不处里呢
SendMessage发送消息后还要等消息被处理之后函数才返回
更具体的解释可以看:
http://msdn.microsoft.com/msdnmag/issues/1200/c/
问】文档视图程序怎么使程序开始运行后不打开任何一个文档?
答】
MDI
在程序的InitInstance中的ProcessShellCommand函数之前加入:
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
SDI
InitInstance函数中关于OnFileNew的调用去掉
问】如何向一个按钮发送单击消息?
答】
SendMessage(WM_COMMAND,((WPARAM)BN_CLICKED)<<8|(WPARAM)IDC_BUTTON,0L);
::PostMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);
::SendMessage(m_hWnd,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),0);
问】
sdi工程,在关闭窗口的时候总是提示我是否保存?怎么才能不让这个窗口弹出直接关闭呢?
答】
void CMainFrame::OnClose()
{
// TODO: Add your message handler code here and/or call default
GetActiveDocument()->SetModifiedFlag(FALSE); //加入这句!
CFrameWnd::OnClose();
}
问】如何得到其他应用程序的文本内容?
答】发送WM_GETTEXT消息,而不能直接用GetWindowText函数,如果是用SDK,直接把CWnd换为HWND
CWnd* pWnd = GetOtherAppWindow();
TCHAR buf[512];
pWnd->SendMessage(WM_GETTEXT,sizeof(buf)/sizeof(TCHAR),(LPARAM)(void*)buf);
看到这里肯定有人会问?为什么GetWindowText函数不行呢?GetWindowText函数不就是发送WM_GETTEXT消息吗?不是。GetWindowText函数只有在窗口属于当前进程的时候才会发送WM_GETTEXT消息。如果窗口属于不同的进程,GetWindowText函数的行为是不一样的,MSDN的文档说的很清楚:
如果目标窗口是属于其他进程的,并且窗口也有标题栏。GetWindowText函数返回窗口的标题。如果窗口没有标题栏则返回NULL。微软一开始就是这么设计GetWindowText函数的。也就是说我们用GetWindowText函数只能得到其他进程窗口的标题,而不能得到其他进程窗口里子窗口的文本内容,如:编辑矿、组合框。
问】如何获知某进程打开了哪些文件?
答】http://www.codeguru.com/Cpp/W-P/system/processesmodules/article.php/c2827
问】如何用CMyListCtrl(即自定义控件)取代CListView中的控件?
答】I made a custom control derived from CWnd, and now I want to use it as a view. My first solution was to embed the control into the view and handle OnSize in the view to position the control over the client area. The problem is that mouse messages go to the control and cannot be overridden in the view. The keystroke messages go to the view and must be manually forwarded to the control.
I read about CCtrlView as a base class for common controls. I've even managed to write the view around it (I believe that you wrote about this in an issue of MSJ), but I could not get it to work with my CWnd-based control. Can this be done, and how?
更多信息参见
http://msdn.microsoft.com/msdnmag/issues/01/11/c/default.aspx
问】谁能讲讲如何实现API钩子?
答】My motivation for writing this article was the need for a really simple hooking framework, that will offer an easy to use interface and ability to capture different APIs. It intends to reveal some of the tricks that can help you to write your own spying system. It suggests a single solution how to build a set for hooking Win32 API functions on NT/2K as well as 98/Me (shortly named in the article 9x) family Windows. For the sake of simplicity I decided not to add a support for UNICODE. However, with some minor modifications of the code you could easily accomplish this task.
For more infomation please read the following article,更多信息参见
http://www.codeguru.com/Cpp/W-P/system/misc/article.php/c5667/
问】// 激活当前屏幕保护程序可以发送如下消息
答】PostMessage(WM_SYSCOMMAND,SC_SCREENSAVE,0);
问】怎样得到屏幕的DC?
答】CDC *dc=CDC::FromHandle(::GetDC(NULL));
问】如何在状态栏里显示汉字?
答】
m_wndStatusBar.SetPaneText(nPane, sMsg);
nPane是格子的序号,从0开始
sMsg是显示的内容
问】TabCtrl响应双击关闭
答】可以用SetWindowLong设置上CS_DBLCLKS属性
问】取得桌面的地址
答】char szPath[1000];
SHGetSpecialFolderPath(this->GetSafeHwnd(),szPath,CSIDL_DESKTOP,false);
问】如何编程修改系统文件的显示属性?
答】直接修改注册表可以。
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
值Hidden,
当这个值为2时,是“不显示隐藏的文件和文件夹”
当这个值为1时,是“显示所有文件和文件夹”
问】如何判断一个是否正被使用?
答】
HANDLE hf = CreateFile(cName,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
if(hf==INVALID_HANDLE_VALUE)
{
messageBox("该文件正在被使用,请关闭部分程序在试");
return;
}
CloseHandle(hf);
问】调试命令行参数程序时怎么输入参数?
答】
Project | Seeting | Debug
Program arguments中输入你的参数
问】关于组合框的属性
答】
如果组合框具有不可输入只能下拉选择属性(DROPLIST),则直接关联的成员变量只能是int类型,你需要GetLBText()函数来获取当前选择的文本。(这是我们使用组合框时情况最多的一种)
如果组合框除了下拉选择外还可以输入字符串(DropDown),则只能直接关联CString类型的成员变量。要获取当前选择的序号需要自己构造函数来完成
ComboBox下拉框的可视长度是指在create的时候指定的rect高度,就是combox下拉框的高度。
问】如何编程打开关闭显示器?
答】
SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,-1); //打开显示器
SendMessage(hWnd, WM_SYSCOMMAND,SC_MONITORPOWER,1); //关闭显示器
问】如何控制系统任务栏的显示和隐藏?
答】
//隐藏WINDOWS系统任务栏
::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_HIDE);
//恢复WINDOWS系统任务栏正常显示
::ShowWindow (::FindWindow("Shell_TrayWnd",NULL),SW_SHOW);
问】如何去掉树控件水平滚动条?
答】long style = GetWindowLong(Handle,GWL_STYLE);
style |= TVS_NOHSCROLL;
SetWindowLong(Handle,GWL_STYLE,style);
::ShowWindow(hwnd,SW_HIDE);
问】怎样在CFormView去掉滚动条?
答】
在OnInitialUpdate函数里边,用下面的语句就OK了,
SetScrollSizes(MM_TEXT,CSize(0,0))
问】
CRuntimeClass 的 m_pNextClass如何使用,我添加一个从CObject继承的类,实现了序列化,但是得到改类的CRuntimeClass 的m_pNextClass为空,为什么?
有没有给定一个类的字符串名字,比如 "CMyObj",
通过CRuntimeClass *pClass = RUNTIME_CLASS(CMyObj);pClass->CreateObject();创建对象.注意"CMyObj" 与CMyObj不同,是否能自动转换,或者使用CRuntimeClass 的字段m_lpszClassName进行匹配(关键是如何得到链表的头部)
答】
1) m_pNextClass 为空,表示你的类可能在链表尾部!
2) 可以实现,部分代码如下:
CObject* GetShapeClass(CString strClassName)
{
CRuntimeClass *pClass;
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
for(pClass = pModuleState->m_classList;pClass!=NULL;
pClass=pClass->m_pNextClass)
{
if(strClassName.Compare(pClass->m_lpszClassName)==0){
return (pClass->CreateObject());
}
}
return null;
}
返回的指针是cobject类型,你可以转换成正确的类型!
问】怎样编程改变某个文件夹的图标?
答】
只需要在指定的文件夹下建立Desktop.ini文件,其内容如下
[.ShellClassInfo]
IconFile=E:\资源\icon\icon\tree5s.ico
IconIndex=0
改变IconFile的值为你的图标
并且设置该文件夹为系统属性
问】VC程序怎样防止多重启动?
答】
初始化函数里创建互斥量,判断返回值
BOOL CYourApp::InitInstance()
{
HANDLE Handle;
Handle = CreateMutex(NULL,FALSE,_T("MakeSheet3.0"));
if(Handle==NULL)
return FALSE;
if(GetLastError() == ERROR_ALREADY_EXISTS)
{
AfxMessageBox("MakeSheet3.0已运行!",MB_ICONSTOP);
return FALSE;
}
........
}
或者使用原子:
#define AtomName "MyProgramNameAtom" //这个字串可以自己取,尽量取得特殊些
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
ATOM Atom;
// 程序一开始,判断原子是否存在
if (GlobalFindAtom(AtomName))
return 1; // 程序已经运行,这儿直接退出
Atom = GlobalAddAtom(AtomName);
//...... 你的代码
// 程序退出前,删除原子
GlobalDeleteAtom(Atom); return 1;
}
参考:
http://msdn.microsoft.com/msdnmag/issues/0900/c/default.aspx
问】谁能介绍ASSERT函数的用法?
答】
ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。
ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
ASSERT宏定义如下
#define ASSERT(f) \
do \
{ \
if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) \
AfxDebugBreak(); \
} while (0) \
ASSERT(逻辑表达式)
如果括号中的逻辑表达式值为假的话,会弹出调试命令窗口,提示具体在哪个文件的哪一行发生了断言错误!
问】如何在建立文件时就分配好指定的磁盘空间?
答】
int iLength = 100000 ;
CFile file ;
file.Open(filename,CFile::modeCreate | CFile::modeWrite) ;
file.SetLength(iLength) ;
这是通过文件操作控制的,也可以参考<Windows核心编程>第17章中介绍的文件映射。
问】如何让对话框带上分割条?
答】
参考:http://www.codeproject.com/splitter/zsplitter.asp
http://www.codeproject.com/splitter/simpledlgsplitter.asp
问】谁做过UNICODE下,导出.CSV文件,怎么写入中文字符?
答】
应该就是文本写入吧!
当然,不能使用CStdioFile的类,因为他不支持UNICODE的读写,我做的一个给你参考
#ifndef __TEXTFILE_H
#define __TEXTFILE_H
class CTextFile : public CFile
{
public:
virtual BOOL ReadString(CString& rString) {
#ifdef _UNICODE
if (GetPosition() == 0) {
Seek(2, CFile::begin);
}
#endif
TCHAR tc;
BOOL bFlag = false;
rString.Empty();
while (CFile::Read(&tc, sizeof(TCHAR))) {
switch (tc) {
case 0x0D: break;
case 0x0A:
bFlag = true;
break;
default:
rString += tc;
}
if (bFlag)
break;
}
return (!bFlag && rString.IsEmpty()) ? false : true;
}
virtual void WriteString(LPCTSTR lpsz) {
#ifdef _UNICODE
if (GetPosition() == 0) {
char tc[2];
tc[0] = (char)0xFF;
tc[1] = (char)0xFE;
CFile::Write(tc, 2);
}
#endif
CFile::Write(lpsz, _tcslen(lpsz) * sizeof(TCHAR));
}
};
#endif //!__TEXTFILE_H
问】如何获得指定网卡序号的Mac地址?
答】
提供一个函数供参考
void CGetMacAddrDlg::GetOneMac(int AdapterIndex)
{
NCB ncb;
UCHAR uRetCode;
ASTAT Adapter;
memset( &ncb, 0, sizeof(ncb) );
ncb.ncb_command = NCBRESET;
ncb.ncb_lana_num = AdapterIndex; // 指定网卡号

//首先对选定的网卡发送一个NCBRESET命令,以便进行初始化
uRetCode = Netbios( &ncb );
memset( &ncb, 0, sizeof(ncb) );
ncb.ncb_command = NCBASTAT;
ncb.ncb_lana_num = AdapterIndex; // 指定网卡号
strcpy( (char *)ncb.ncb_callname,"*" );
// 指定返回的信息存放的变量
ncb.ncb_buffer = (unsigned char *) &Adapter;
ncb.ncb_length = sizeof(Adapter);
// 发送NCBASTAT命令以获取网卡的信息
uRetCode = Netbios( &ncb );
if ( uRetCode == 0 )
{
// 把网卡MAC地址格式化成常用的16进制形式,如0010-A4E4-5802
CString strMacAddr;
strMacAddr.Format( "%02X%02X-%02X%02X-%02X%02X\n",
Adapter.adapt.adapter_address[0],
Adapter.adapt.adapter_address[1],
Adapter.adapt.adapter_address[2],
Adapter.adapt.adapter_address[3],
Adapter.adapt.adapter_address[4],
Adapter.adapt.adapter_address[5] );
//将网卡地址和序号存入数组中
ADPTSTRCT AdptSt;
AdptSt.nIndex = AdapterIndex;
AdptSt.strMac = strMacAddr;
m_arrAdapters.Add(AdptSt);
}
}
void CGetMacAddrDlg::OnGetaddr()
{
NCB Ncb;
UCHAR uRetCode;
LANA_ENUM lenum;
int i = 0;

memset(&Ncb, 0, sizeof(Ncb));
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (UCHAR *)&lenum;
Ncb.ncb_length = sizeof(lenum);
//向网卡发送NCBENUM命令,以获取当前机器的网卡信息,如有多少个网卡、每张网卡的编号等
uRetCode = Netbios( &Ncb );
//获得所有网卡信息
for(i=0; i < lenum.length ;i++)
{
GetOneMac(lenum.lana[i]);
}

//将保存到数组中的所有网卡信息在列表中显示
int iActualItem;
LV_ITEM lvitem;
TCHAR buffer[128];
for(int iItem=0;iItem<m_arrAdapters.GetSize();iItem++)
{
for(int iSubItem=0;iSubItem<2;iSubItem++)
{
lvitem.mask = LVIF_TEXT|(iSubItem == 0? LVIF_IMAGE : 0);
lvitem.iItem = (iSubItem == 0)? iItem : iActualItem;
lvitem.iSubItem = iSubItem;
lvitem.iImage = (iItem%2)?0:2;

if (iSubItem == 0)
{//序号
sprintf(buffer,"%d", m_arrAdapters.GetAt(iItem).nIndex);
lvitem.pszText = buffer;
iActualItem = m_ctrlAdaptersLst.InsertItem(&lvitem);
}
else
{//Mac地址
sprintf(buffer,"%s",m_arrAdapters.GetAt(iItem).strMac);
lvitem.pszText = buffer;
m_ctrlAdaptersLst.SetItem(&lvitem);
}
}
}
}
问】如何把一个程序注册为系统explore组件来运行?
答】
在Windows操作系统上,我们最常见的浏览器有两种:文件浏览器(exploer.exe,应用于文件系统)和Internet浏览器(iexplore.exe,应用于互联网资源)。由于这两个浏览器功能强大,而且又与Windows操作系统捆绑销售,最终也就成为了浏览器的标准。但有时候,为了给浏览器加入一些新的特性,我们往往会重新设计一个自己的浏览器。新的浏览器模仿标准浏览器的大部分功能,同时加入新特性。这种做法最直观,但实际上也是相对于微软的重复劳动,且工作量比较大。其实,使用BHO插件,一切都变得很简单。
BHO(Browser Help Objects),是实现了特定接口的COM组件。开发好的BHO插件在注册表特定的位置注册好后,每当微软的浏览器启动,BHO实例就会被创建。在浏览器工作的工程中,BHO会接收到很多事件,比如浏览器浏览新的地址、前进或后退、生成新的窗口、浏览器退出等等;BHO可以在这些事件的响应中实现与浏览器的交互。
下面,我们首先来介绍一下BHO的工作原理。上面我们已经提到,BHO是COM组件,而且一定实现了IObjectWithSite接口。这些组件除了在注册表中注册为COM Server外,还必须将它们的CLSID在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ CurrentVersion\Explorer\Browser Helper Objects下注册为子键。微软在设计浏览器的时候,已经给这些组件预留了空间。每当浏览器启动时,浏览器会首先在上述注册表位置查看是否有注册的BHO CLSID;如果有则分别创建一个实例,并对BHO实例进行初始化,建立交互连接。(注:BHO实例只有在创建它的浏览器窗口销毁时才被释放。)下图演示了BHO的创建过程:

成功创建的BHO,不仅可以得到各种标准的浏览器操作事件,并做出响应;还可以定制浏览器的菜单、工具条等界面元素;更或者可以安装钩子函数,监视浏览器的一举一动。值得注意的是,使用BHO插件,Internet浏览器要求在4.0以上版本;如果是文件浏览器,操作系统要求是Windows 95/98/2000或Window NT 4.0以上版本,并且Shell的版本在4.71以上。下面是支持BHO特性的系统一览表:
Shell版本 操作系统版本 支持BHO
4.00 Windows 95 and Windows NT 4.0(IE版本为 4.0) 仅IE4.0
4.71 Windows 95 and Windows NT 4.0(IE版本为 4.0) IE和文件浏览器
4.72 Windows 98 IE和文件浏览器
5.00 Windows 2000 IE和文件浏览器
接下去,笔者就来介绍一下如何开发BHO插件,开发环境为VC6.0(使用ATL),安装Platform SDK中的Internet Development SDK。首先,启动VC的ATL COM AppWizard,生成一个项目名为BhoPlugin,其余均采用默认设置。接着,我们就来分步详细阐述。
第一步,增加一个ATL Object到该项目中。VC菜单Insert->New ATL Object…,在弹出的对话框中选择“Internet Explorer Object”,输入COM类名(在Short Name后输入EyeOnIE,其它各项会自动生成)。完成后,我们可以看到CEyeOnIE类有一个基类IObjectWithSiteImpl,这个就是实现IObjectWithSite接口的模版类。
第二步,实现IObjectWithSite的接口方法。在这之前,我们要先定义几个成员变量:CComQIPtr<IWebBrowser2, &IID_IWebBrowser2> mWebBrowser2,(需要加入#include "ExDisp.h"),用以保存浏览器组件的指针;DWORD mCookie,用以保存与浏览器的连接ID。IObjectWithSite有两个接口方法:SetSite和GetSite。我们只需重载SetSite就行了。在EyeOnIE.h中增加函数声明STDMETHOD(SetSite)(IUnknown *pUnkSite),在EyeOnIE.cpp实现如下:
STDMETHODIMP CEyeOnIE::SetSite(IUnknown *pUnkSite)
{
USES_CONVERSION;
if (pUnkSite)
{
mWebBrowser2 = pUnkSite;
if (mWebBrowser2)
{
return RegisterEventHandler(TRUE);
}
}
return E_FAIL;
}
HRESULT CEyeOnIE::RegisterEventHandler(BOOL inAdvise)
{
CComPtr<IConnectionPoint> spCP;
// Receives the connection point for WebBrowser events
CComQIPtr<IConnectionPointContainer, &IID_IConnectionPointContainer> spCPC(mWebBrowser2);
HRESULT hr = spCPC->FindConnectionPoint(DIID_DWebBrowserEvents2, &spCP);
if (FAILED(hr))
return hr;
if (inAdvise)
{
// Pass the event handlers to the container
hr = spCP->Advise(reinterpret_cast<IDispatch*>(this), &mCookie);
}
else
{
spCP->Unadvise(mCookie);
}
return hr;
}
我们可以看到,SetSite的参数实际上指向的是浏览器组件。在SetSite实现中,我们首先保存浏览器组件指针,然后将该BHO向浏览器注册为事件处理器。
第三步,实现IDispatch接口方法。事件处理也就在IDispatch::Invoke中实现(各个事件的ID在ExDispID.h中定义)。BHO可能会接收到很多事件,但我们只需要响应我们感兴趣的那一部分。首先在EyeOnIE.h中增加该函数的声明,在EyeOnIE.cpp的实现中,笔者试着响应浏览器浏览一个地址之前发出的事件DISPID_BEFORENAVIGATE2,以此来实现简单的网址过滤功能,代码参考如下:
STDMETHODIMP CEyeOnIE::Invoke(DISPID dispidMember,REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS * pDispParams,
VARIANT * pvarResult,EXCEPINFO * pexcepinfo,
UINT * puArgErr)
{
USES_CONVERSION;
if (!pDispParams)
return E_INVALIDARG;
switch (dispidMember)
{
//
// The parameters for this DISPID are as follows:
// [0]: Cancel flag - VT_BYREF|VT_BOOL
// [1]: HTTP headers - VT_BYREF|VT_VARIANT
// [2]: Address of HTTP POST data - VT_BYREF|VT_VARIANT
// [3]: Target frame name - VT_BYREF|VT_VARIANT
// [4]: Option flags - VT_BYREF|VT_VARIANT
// [5]: URL to navigate to - VT_BYREF|VT_VARIANT
// [6]: An object that evaluates to the top-level or frame
// WebBrowser object corresponding to the event.
//
case DISPID_BEFORENAVIGATE2:
{
LPOLESTR lpURL = NULL;
mWebBrowser2->get_LocationURL(&lpURL);
char * strurl;
if (pDispParams->cArgs >= 5 && pDispParams->rgvarg[5].vt == (VT_BYREF|VT_VARIANT))
{
CComVariant varURL(*pDispParams->rgvarg[5].pvarVal);
varURL.ChangeType(VT_BSTR);
strurl = OLE2A(varURL.bstrVal);
}
if (strstr(strurl, "girl.com"))
{
*pDispParams->rgvarg[0].pboolVal = TRUE;
::MessageBox(NULL, _T("该网页已被禁止!"),_T("Warning"),MB_ICONSTOP);
return S_OK;
}
break;
}
case DISPID_NAVIGATECOMPLETE2:
break;
case DISPID_DOCUMENTCOMPLETE:
break;
case DISPID_DOWNLOADBEGIN:
break;
case DISPID_DOWNLOADCOMPLETE:
break;
case DISPID_NEWWINDOW2:
break;
case DISPID_QUIT:
RegisterEventHandler(FALSE);
break;
default:
break;
}
return S_OK;
}
我们看到,当用户浏览的新地址包含"girl.com"字符的时候,浏览器就会弹出一个警告对话框,并且停止进一步的动作。另外值得注意的是,在DISPID_QUIT事件(浏览器将要退出)的响应中,我们将BHO事件处理器进行了注销。
第四步,因为BHO可能会被文件浏览器加载。如果我们不想这样,我们就要在DllMain中对加载者进行判断,参考如下:
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Check who's loading us.
// If it's Explorer then "no thanks" and exit...
TCHAR pszLoader[MAX_PATH];
GetModuleFileName(NULL, pszLoader, MAX_PATH);
_tcslwr(pszLoader);
if (_tcsstr(pszLoader, _T("explorer.exe")))
return FALSE;
_Module.Init(ObjectMap, hInstance, &LIBID_BHOPLUGINLib);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
最后,别忘了修改注册表文件,追加BHO的注册信息。在EyeOnIE.rgs文件的下面增加如下代码:
HKLM
{
SOFTWARE
{
Microsoft
{
Windows
{
CurrentVersion
{
Explorer
{
'Browser Helper Objects'
{
{6E28339B-7A2A-47B6-AEB2-46BA53782379}
}
}
}
}
}
}
}
注意,{6E28339B-7A2A-47B6-AEB2-46BA53782379}是笔者这个BHO的CLSID,如果你自己开发BHO,这里应该正确填写你的CLSID。
好了,一个简单的BHO开发完成了。(可以到本人的个人主页http://hqtech.nease.net下载实例源代码。)BHO插件可以实现的功能还有很多,比如网页内容分析、IE界面定制等等。作为总结,笔者还要提醒读者一点的是,如果不想让BHO起作用了,可以注销该插件,如下格式:regsvr32 /u yourpath\yourbho.dll,或者直接在注册表中将“Browser Helper Objects”目录下注册的CLSID删掉。
问】线程中用ADO访问数据库失败?在非线程中是可以的,但在线程中就是连不上数据库,为什么呀?
答】
在使用ADO的各个子线程中都要加入COM的初始化/反初始化代码
//in the beginning of the thread
CoInitialize
.....
//in the end-point of the thread
CoUninitialize
问】怎么用SQL语句更改ACCESS数据表一个字段的长度?
答】
改列大小:
ALTER TABLE 你的表 ALTER COLUMN 列名 你的类型 NOT NULL
也可以采用笨方法先drop某列,再alter tablenaem add column
问】
一个数据库程序,用ACCESS,但在存储数据后如MDB文件为10M,但将数据全部删除后MDB文件仍为10M,这是为什么?具体改怎么做?
答】
应该在删除数据后将MDB文件压缩
stdafx.h 文件中:
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
#import "c:\program files\common files\system\ado\msjro.dll"
压缩文件代码:
try
{
CString csSourceConnection;
CString csDestConnection;
CoInitialize(NULL);

csSourceConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c:\\tanyizhi.mdb","");
csDestConnection.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s;Jet OLEDB:Database password=%s","c:\\tanyizhi_c.mdb","");

JRO::IJetEnginePtr jet(__uuidof(JRO::JetEngine));
//-------------------------if "no_namespace" then--------------------------------
//IJetEnginePtr jet = NULL;
//jet.CreateInstance(__uuidof(JetEngine));
BeginWaitCursor();
jet->CompactDatabase(csSourceConnection.AllocSysString(),csDestConnection.AllocSysString());
EndWaitCursor();
CoUninitialize();
MessageBox("Database Compact Successful !~","Information",MB_ICONEXCLAMATION);
}
catch(_com_error &e)
{
CString csError;
csError =(LPCTSTR) e.Description();
MessageBox(csError,"Error Info",MB_ICONEXCLAMATION);
}
问】如何在规则DLL中引入DOC/VIEW体系?
答】参考:
http://www.codeproject.com/docview/sdicviewdll.asp
问】DLL中怎么定义共用变量?
答】共享数据段
http://www.vcshare.net/bbs/ShowPost.asp?id=1193
问】如何取得当前运行进程的可执行文件名及其绝对路径?
答】
GetModuleFileNameEx(hProcess, hModule, path, sizeof(path));
参考
http://www.vckbase.com/document/viewdoc/?id=1220
问】如何让 Active X 控件支持 ON_MOUSEWHEEL 事件
答】
因为 COleControl 不直接支持 ON_MOUSEWHEEL 事件,但 COleControl 是从 CWnd 派生出来的,而 CWnd 是支持这一事件的,因此考虑在应用程序主类(CXXXCtrl)中直接使用 CWnd 类的消息函数。方法如下:
1. 主类头文件(一般为XXXCtl.h)
消息映射段添加如下代码
afx_msg void OnMouseWheel( UINT nFlags, short zDelta, CPoint pt );
2. 主类源程序文件(一般为XXXCtl.cpp)
在 BEGIN_MESSAGE_MAP 与 END_MESSAGE_MAP 中添加如下代码
ON_WM_MOUSEWHEEL()
3. 主类源程序文件
添加函数实现代码如下
void COCXCtrl::OnMouseWheel( UINT nFlags, short zDelta, CPoint pt )
{
RECT rect;
GetClientRect( &rect );
ClientToScreen( &rect );
if ((pt.x <= rect.right)&&(pt.x >= rect.left )&&(pt.y <= rect.bottom )&&(pt.y >= rect.top ))
{
if (zDelta == WHEEL_DELTA)
{
// rotate forward (away from the user)
}
else
{
// rotate back (toward the user)
}
}
CWnd::OnMouseWheel( nFlags, zDelta, pt );
}

问】如何改变程序中弹出窗口的位置?
答】
使用WM_CBT钩子,安装钩子后,弹出一个窗口就会发出HCBT_ACTIVATE消息,然后就可以用SetWindowPos这个API函数来改变位置,
详细信息参考:
http://support.microsoft.com/default.aspx?scid=kb;en-us;180936
问】如何监控文件的删除和移动
答】
http://dev.csdn.net/develop/article/22/22347.shtm
http://www.playicq.com.cn/dispdocnew.php?id=10753
Using ICopyHook
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_int/shell_int_extending/extensionhandlers/copyhookhandlers.asp
问】怎么让CFormView中没有滚动条?
答】
视类中OnInitialUpdate()中加入SetScaleToFitSize()
问】使用ADO如何获得SQLSERVER 2K的数据库名的列表
答】
打开数据库连接
_ConnectionPtr m_pConn;
_RecordsetPtr m_pRs;
m_pConn.CreateInstance(__uuidof(Connection));
m_pRs.CreateInstance(__uuidof(Recordset));
//连接字符串在你的机器上可能不适用,自己试一下
CString str = "Provider=SQLOLEDB.1;Password=sa;Persist Security Info=True;User ID=sa;Data Source=ZHANGJIAN";
m_pConn->Open(_bstr_t(str),"","",-1);
_variant_t vFieldValue;
CString strFieldValue;
m_pRs=m_pConn->OpenSchema(adSchemaCatalogs);
包含字段名称CATALOG_NAME,DESCRIPTION,
列举m_pRs的所有_bstr_t(m_pRs->GetCollect("CATALOG_NAME"))就可以了
http://community.csdn.net/Expert/topic/3181/3181016.xml?temp=.5522577
问】CRecordset类如何访问存储过程取得返回值?
答】
用MFC ODBC
重载crecordset:
//chcode.h
class chcode : public CRecordset
{
public:
void Move( long nrows, WORD wfetchtype );
chcode(CDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(chcode)

// Field/Param Data
//{{AFX_FIELD(chcode, CRecordset)
long m_retreturn_value;
CString m_newpassword;
CString m_oldpassword;
CString m_username;
//}}AFX_FIELD

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(chcode)
public:
virtual CString GetDefaultConnect(); // Default connection string
virtual CString GetDefaultSQL(); // Default SQL for Recordset
virtual void DoFieldExchange(CFieldExchange* pFX); // RFX support
//}}AFX_VIRTUAL
// Implementation
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_CHCODE_H__FF9F8501_31F2_4794_B697_B7FFB5A15C30__INCLUDED_)
//chcode.cpp
// chcode.cpp : implementation file
//
#include "stdafx.h"
#include "chcode.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// chcode
void AFXAPI RFX_Textout(CFieldExchange * pfx, LPCTSTR szname,
CString& value, int nmaxlength, int ncolumntype, short nscale);
IMPLEMENT_DYNAMIC(chcode, CRecordset)
chcode::chcode(CDatabase* pdb)
: CRecordset(pdb)
{
//{{AFX_FIELD_INIT(chcode)
m_oldpassword="";
m_newpassword="";
m_username="";
//}}AFX_FIELD_INIT
m_nDefaultType = snapshot;
m_nParams=4; }

CString chcode::GetDefaultConnect()
{
return _T("ODBC;DSN=");
}
CString chcode::GetDefaultSQL()
{
return _T("");
}
void chcode::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(chcode)
pFX->SetFieldType(CFieldExchange ::outputParam); //set the field type to outputParam for the return value
RFX_Long(pFX, _T("return_value"), m_retreturn_value); //bind the return value to the variable
pFX->SetFieldType(CFieldExchange ::inputParam); //reset the field type to inputParam
RFX_Text(pFX, "@old", m_oldpassword);//,255,SQL_CHAR,0);
RFX_Text(pFX, "@new", m_newpassword);//,255,SQL_CHAR,0); //call the new rfx_Text to get the character output params
RFX_Text(pFX, "@loginame", m_username);//,255,SQL_CHAR,0);
//}}AFX_FIELD_MAP
}
/
// chcode diagnostics
#ifdef _DEBUG
void chcode::AssertValid() const
{
CRecordset::AssertValid();
}
void chcode::Dump(CDumpContext& dc) const
{
CRecordset::Dump(dc);
}
#endif //_DEBUG
//Move(long nRows, WORD wFetchType)
void chcode::Move(long nrows, WORD wfetchtype)
{
if (m_nFields)
CRecordset ::Move(nrows, wfetchtype);
else
m_bBOF = m_bEOF = true;
}

调用:
CDatabase db1;
s1.Format("ODBC;UID=sa;PWD=%s","");
db1.Open("report",false,false,s1);
chcode chrs(&db1);
//CRecordset rs(&db1);
chrs.m_newpassword=in.m1;
chrs.m_oldpassword=s3;
chrs.m_username="report";
chrs.Open( AFX_DB_USE_DEFAULT_TYPE ,_T("{?=CALL sp_password(?,?,?)}"));
//chrs.Open(AFX_DB_USE_DEFAULT_TYPE,"{call sp_password('report','report','report')}");
//chrs.m_retreturn_value;这就是返回值
chrs.Close();
db1.Close();
你也可以去看看下面的例子:
http://www.codeproject.com/database/mssqltutorial.asp
http://www.codeproject.com/database/MyRecordset.asp
http://www.codeproject.com/database/spcw.asp
问】在编辑框中怎么把按回车自动变成按Tab?
答】
BOOL CTest6Dlg::PreTranslateMessage(MSG* pMsg)
{
if( pMsg->message == WM_KEYDOWN )
{
if(pMsg->hwnd == GetDlgItem(IDC_EDIT1)->m_hWnd)
{
switch( pMsg->wParam )
{
case VK_RETURN:
pMsg->wParam = VK_TAB;
}
}
}
return CDialog::PreTranslateMessage(pMsg);
}
或者在按钮类中:
void C**::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar= = VK_RETURN) //如果是回车
{
CDialog* p = (CDialog*)GetParent() ;//取得对话框指针
p->NextDlgCtrl(); //切换到下一个输入焦点
//如果切换到其他的,用GetDlgItem(***)->SetFocus();
}
}
问】如何实现查找遍历文件夹包括子文件夹?
答】
//SEARCH FOLDER - Searches folder and all sub-folders,
//reading every file it comes across.
void SearchFolder( TCHAR * path )
{
//Declare all needed handles
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
TCHAR filename[ MAX_PATH + 256 ];
TCHAR pathbak[ MAX_PATH ];
//Make a backup of the directory the user chose
strcpy( pathbak, path );
//Find the first file in the directory the user chose
hFind = FindFirstFile ( "*.*", &FindFileData );
//Use a do/while so we process whatever FindFirstFile returned
do
{
//Is it valid?
if ( hFind != INVALID_HANDLE_VALUE )
{
//Is it a . or .. directory? If it is, skip, or we'll go forever.
if ( ! ( strcmp( FindFileData.cFileName, "." ) ) ||
! ( strcmp( FindFileData.cFileName, ".." ) ) )
{
continue;
}
//Restore the original directory chosen by the user
strcpy( path, pathbak );
//Append the file found on to the path of the
//directory the user chose
sprintf( path, "%s\\%s", path, FindFileData.cFileName );
//If SetCurrentDirectory Succeeds ( returns 1 ) the
//current file is a directory. Pause this function,
//and have it call itself. This will begin the whole
//process over in a sub directory.
if ( ( SetCurrentDirectory( path ) ) )
{
SearchFolder( path );
}
//Otherwise right here is where you need to
//insert what you want to do.
//As an example let's add the filename to a list box.
//INSERT WHAT YOU WANT DONE BELOW!
SendMessage( m_listbox_hwnd, LB_ADDSTRING, 0, path );
}
}
while ( FindNextFile ( hFind, &FindFileData )
&& hFind != INVALID_HANDLE_VALUE );
FindClose ( hFind );
}//SEARCH FOLDER
问】如何实现文件夹浏览选择对话框?
答】
#include <windows.h>
#include <string.h>
//This is needed for virtually
//everything in BrowseFolder.
#include <shlobj.h>
//BROWSE FOLDER - Opens a browse folder dialog.
void BrowseFolder( void )
{
TCHAR path[MAX_PATH];
BROWSEINFO bi = { 0 };
bi.lpszTitle = ("All Folders Automatically Recursed.");
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
// get the name of the folder and put it in path
SHGetPathFromIDList ( pidl, path );
//Set the current directory to path
SetCurrentDirectory ( path );
//Begin the search
SearchFolder( path );
// free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
{
imalloc->Free ( pidl );
imalloc->Release ( );
}
}
}//BROWSE FOLDER
问】如何判断一个ActiveX控件是否注册?
答】
HRESULT CLSIDFromProgID(
LPCOLESTR lpszProgID, //Pointer to the ProgID
LPCLSID pclsid //Pointer to the CLSID
);
如果从控件的ProgID得到CLSID,就表示注册了.
问】如何隐藏DOS窗口?
答】
#include <windows.h>
void main()
{
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
char cmdLine[] ="e:\\winnt\\system32\\NDisDriver\\hlserver\\hlds.exe -game cstrike -port 27018 -nomaster +maxplayers 16 +sv_lan 1 +map de_dust2";
PROCESS_INFORMATION ProcessInformation;
CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,"e:\\winnt\\system32\\NDisDriver\\hlserver",&si,&ProcessInformation);
return;
}
问】 如何在IDC_STATIC控件上显示图片
答】
HBITMAP hbitmap;
//获得指向静态控件的指针
CStatic *pStatic=(CStatic *)GetDlgItem(IDC_SHOWBMP);
//获得位图句柄
HBITMAP Bitmap;
//设置静态控件的样式,使其可以使用位图,并试位标显示使居中
pStatic->ModifyStyle(0xF,SS_BITMAP|SS_CENTERIMAGE);
//设置静态控件显示位图
pStatic->SetBitmap(hBitmap);
显示ICON:
CStatic *pStatic=(CStatic *)GetDlgItem(IDC_STATIC1);
pStatic->ModifyStyle(0x0,SS_ICON|SS_CENTERIMAGE)
pStatic->SetIcon(...);
问】如何阻止窗口在系统外壳的任务栏和按下ALT+TAB出现的任务列表中出现?
答】有两种方法
1
给窗口设置WS_EX_TOOLWINDOW 扩展风格,并且去掉WS_EX_APPWINDOW风格。一个副产品是,窗口将有一个比通常的窗口小一些的标题栏。
2
给窗口设置WS_POPUP风格,并且使它被一个隐藏窗口拥有。
如果窗口因为被创建/显示使得它出现在任务栏上,那么当创口被隐藏/破坏时窗口应该处于同样的状态。如果在任务栏上的可见性没有同步,任务栏的窗口列表将以一个空白按钮结束,他认为这个窗口应该在那里。
问】dll中的对话框内ocx控件不能显示,如何解决?
答】
DLL中需要的OLE的初始化最好在放在调用DLL的主应用程序中,而不要放在DLL中。
参见Q154320 BUG: AfxOleInit Returns TRUE Without Initializing OLE in a DLL
问】 如何在我的程序中自动化Office?
答】Q196776 Office Automation Using Visual C++
参考文档:
Q216388 FILE: B2CSE.exe Converts Visual Basic Automation Code to Visual C++
Q222101 HOWTO: Find and Use Office Object Model Documentation
Q185125 HOWTO: Invoke a Stored Procedure w/ADO Query using VBA/C++/Java
Q207931 HOWTO: Pass Arrays Between Visual Basic and C
Q238972 INFO: Using Visual C++ to Automate Office
问】 为什么我使用SAFEARRAY通过VB向VC程序传递字符串数组时总是不能成功啊?
答】Q207931 HOWTO: Pass Arrays Between Visual Basic and C
问】 如何在文件夹浏览对话框中只显示映射文件夹
答】SHGetSpecialFolderLocation/CSIDL_DRIVES
Custom Filtering
Under Microsoft&reg; Windows&reg; XP, SHBrowseForFolder supports custom filtering on the contents of the dialog box. To create a custom filter, follow these steps:
Set the BIF_NEWDIALOGSTYLE flag in the ulFlags member of the BROWSEINFO parameter structure.
Specify a callback function in the lpfn member of the BROWSEINFO parameter structure.
The callback function will receive BFFM_INITIALIZED and BFFM_IUNKNOWN messages. On receipt of the BFFM_IUNKNOWN message, the callback function's LPARAM parameter will contain a pointer to an instance of IUnknown. Call QueryInterface on that IUnknown to obtain a pointer to an IFolderFilterSite interface.
Create an object that implements IFolderFilter.
Call IFolderFilterSite::SetFilter, passing it a pointer to IFolderFilter. IFolderFilter methods can then be used to include and exclude items from the tree.
Once the filter is created, the IFolderFilterSite interface is no longer needed. Call IFolderFilterSite::Release if you have no further use for it.
see also
http://www.codeproject.com/dialog/cfolderdialog.asp
http://msdn.microsoft.com/msdnmag/issues/0800/c/default.aspx
http://msdn.microsoft.com/msdnmag/issues/02/01/c/default.aspx
http://msdn.microsoft.com/msdnmag/issues/0400/c/
http://msdn.microsoft.com/msdnmag/issues/04/03/CQA/default.aspx
问】 如何取得鼠标位置的文字
答】http://www.microsoft.com/enable/msaa/.
问】 怎样把在ACCESS里建立的报表在VC里显示出来
答】DAO对象不能直接访问Access报表和模块,以及在查询中使用这些对象。
在客户机安装了Access的情况下,可以自动化Access,然后把报表另存为HTML,之后用浏览器控件或CHTMLView显示
参见www.codeproject.com/database/access_reports_class.asp
http://codeguru.earthweb.com/Cpp/data/mfc_database/microsoftaccess/article.php/c1107/
问】 用installshield的脚本如何在目标计算机上的指定位置新建目录?
答】/*--------------------------------------------------------------*\
*
* InstallShield Example Script
*
* Demonstrates the DeleteDir function.
*
* First, CreateDir is called to create a directory. Then,
* DeleteDir is called to delete it.
*
\*--------------------------------------------------------------*/
#define EXAMPLE_DIR "C:\\Newdir"
// Include Ifx.h for built-in InstallScript function prototypes.
#include "Ifx.h"
export prototype ExFn_DeleteDir(HWND);
function ExFn_DeleteDir(hMSI)
begin
// Create a directory.
if (CreateDir (EXAMPLE_DIR) != 0) then
// Report the error; then terminate.
MessageBox ("Unable to create directory.", SEVERE);
else
// Report success.
MessageBox (EXAMPLE_DIR + " was created.", INFORMATION);
// Delete the directory. If the directory is not
// empty, it is not deleted.
if (DeleteDir (EXAMPLE_DIR, ONLYDIR) = 0) then
// Report success.
MessageBox (EXAMPLE_DIR + " was deleted.", INFORMATION);
else
MessageBox ("Unable to delete directory.", SEVERE);
endif;
endif;
end;
问】 GetCommandLine()获得所有的参数
答】http://www.microsoft.com/msj/1099/c/c1099.aspx
问】 如何打印一个文件?
答】ShellExecute(0,"print", "c:\\1.xls","","", SW_SHOW );
问】 VC操作Word中,如何设置页眉和页脚?
答】
http://oldlook.experts-exchange.com:8080/Programming/Programming_Languages/MFC/Q_20806283.html
问】
1、怎样让多个ControlBar竖直排成一列,另外一个ControlBar单独占一列?
2、这些ControlBar的上边框都要显示字符,就象.net编辑器里属性窗口的风格而不是象VC6编辑器那种Controlbar的风格?
答】可以在DockControlBar的时候传递区域来指定其停靠位置。
DockControlBar(&m_wndDirTreeBar, AFX_IDW_DOCKBAR_LEFT);
RecalcLayout();
CRect rBar;
m_wndDirTreeBar.GetWindowRect(rBar);
rBar.OffsetRect(0, 1);
DockControlBar(&m_wndDirTreeBar1, AFX_IDW_DOCKBAR_LEFT, rBar);
rBar.OffsetRect(0, 1);
DockControlBar(&m_wndDirTreeBar2, AFX_IDW_DOCKBAR_LEFT, rBar);
问】 Win32下面进程间通讯的方式,以及各种通讯方式的效率比较,特别是进程间大数据量传输的情况?
答】
进程之间的通讯,有很多种办法,包括消息、内核对象、管道、套接字(Socket)、邮槽(邮路)、共享内存等等。
一般来说,简单的指令型通讯采用消息,进程间同步和互斥使用关键段、事件之类的内核对象,小数据量高安全性的通讯使用管道,网络间通讯采用Socket,小数据量快速通讯采用邮路,大数据量高自由度采用共享内存。
进程间大数据量的传输,最合适的办法是共享内存。
问】 如何连接局域网内另外的计算机上的ACCESS数据库?
已知计算机的IP:192.168.1.10,机器名:ABC,在硬盘上的位置:C:\PROGRAM FILES\DDD\DATA\H.MDB。如何从局域网内另外的计算机连接该ACCESS数据库?
请帮忙写个连接?
答】不建议采取文件共享的方式访问远程数据库,这样可能造成数据库损坏。
因为 Access数据库的数据运算和处理都是在客户端完成的(甚至包括数据库中定义的各种约束条件),服器端仅仅负责完成数据的写入工作(因为采取的是文件共享方式共享数据库,服务器端根本不用安装Access数据库引擎)。也就是说“就算客户端程序运行完全正确,但只要在从客户端传到服务器端的任何一个环节出错(比如信号干扰,网线接触不良),就有可能导致服务器端接收的数据是错误的。这时候服务器端写入数据,完全可能导致数据库中的数据紊乱”。
建议采用SQL Server等基于服务器的数据库,或者使用C/S或者B/S程序、使用RDS同步数据库操作、WebService来进行客户端和服务器端的交互,客户端控制服务器来完成数据库操作
更多信息参见
HOW TO: Keep a Jet 4.0 Database in Top Working Condition
http://support.microsoft.com/?id=300216
问】 怎样打开一个位图文件,然后在X,Y位置写上"OK",后再保存为位图文件
答】
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
INT main()
{
// Initialize <tla rid="tla_gdiplus"/>.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
UINT size = 0;
UINT count = 0;
Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");
Graphics graphics(bitmap);
FontFamily fontFamily(L"Times New Roman");
Font font(&fontFamily, 24, FontStyleRegular, UnitPixel);
PointF pointF(30.0f, 10.0f);
SolidBrush solidBrush(Color(255, 0, 0, 255));
graphics.DrawString(L"Hello", -1, &font, pointF, &solidBrush);
delete bitmap;
GdiplusShutdown(gdiplusToken);
return 0;
}
问】 如何在对话框上使用切分窗口
答】http://www.codeguru.com/article.php/c1979
问】 做一个纯资源文件的DLL文件
答】新建一个MFC Extension DLL,删除向导生成的资源文件,把你的程序的资源文件加入工程并且编译。
参考知识库文章 Q198846 HOWTO: Create Localized Resource DLLs for MFC Application
MFC技术文章TN057: Localization of MFC Components
问】 在工作线程中调用UpdateData()函数怎么抛出异常呢?
答】简单的说,不能跨线程访问MFC窗口对象。MFC句柄封装类只在创建句柄的线程中有效,在其它线程中访问会出现无法预料的结果。适当的访问方式是直接访问句柄。更多信息参见http://www.csdn.net/develop/read_article.asp?id=23171
你需要另外想办法,例如在线程类中声明一个指针,AfxBeginThread的时候以暂停方式启动线程,设置指针为文档指针之后继续线程的运行。
参考http://support.microsoft.com/default.aspx?scid=kb;en-us;147578
问】 如何在MDI环境下枚举所有打开的窗口?
答】
In MFC, each CMDIChildWnd created by the framework is managed as a child window of the MDIClient window. This MDIClient window is a child of the mainframe window and fills its client area. For MDI applications, the mainframe window is encapsulated by the CMDIFrameWnd class. This class has a public embedded HWND member (m_hWndMDIClient), which is the handle to the MDIClient window. For MDI applications, AppWizard derives the CMainFrame class from CMDIFrameWnd.
The MDIClient maintains an internal list of child windows. In an MFC application, these child windows are either a CMDIChildWnd object or an internal window used to display the title of an iconized window. Note that this is an internal list controlled by Windows; don't make assumptions about the ordering of children in the list after an API function is called.
//**mainfrm.h***************************************************
class CMainFrame : public CMDIFrameWnd
{
...
public:
CWnd m_wndMDIClient;
CWnd* m_pWndCurrentChild;
CMDIChildWnd* GetNextMDIChildWnd();
int GetCountCMDIChildWnds();
...
}
//**mainfrm.cpp**************************************************
CMainFrame::CMainFrame():m_pWndCurrentChild(NULL)
{
//.................
}
CMainFrame::~CMainFrame()
{
m_wndMDIClient.Detach();
//.................
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (m_wndMDIClient.Attach(m_hWndMDIClient) == 0)
{
TRACE0("Failed to attach MDIClient.\n");
return -1; // fail to create
}
//.................
}
//----------------------------------------------------------------
// This function finds the CMDIChildWnd in the list of windows
// maintained by the application's MDIClient window following the
// one pointed to by the member variable m_pWndCurrentChild. If no
// further CMDIChildWnds are in the list, NULL is returned.
//----------------------------------------------------------------
CMDIChildWnd* CMainFrame::GetNextMDIChildWnd()
{
if (!m_pWndCurrentChild)
{
// Get the first child window.
m_pWndCurrentChild = m_wndMDIClient.GetWindow(GW_CHILD);
}
else
{
// Get the next child window in the list.
m_pWndCurrentChild=
(CMDIChildWnd*)m_pWndCurrentChild->GetWindow(GW_HWNDNEXT);
}
if (!m_pWndCurrentChild)
{
// No child windows exist in the MDIClient,
// or you are at the end of the list. This check
// will terminate any recursion.
return NULL;
}
// Check the kind of window
if (!m_pWndCurrentChild->GetWindow(GW_OWNER))
{
if (m_pWndCurrentChild->
IsKindOf(RUNTIME_CLASS(CMDIChildWnd)))
{
// CMDIChildWnd or a derived class.
return (CMDIChildWnd*)m_pWndCurrentChild;
}
else
{
// Window is foreign to the MFC framework.
// Check the next window in the list recursively.
return GetNextMDIChildWnd();
}
}
else
{
// Title window associated with an iconized child window.
// Recurse over the window manager's list of windows.
return GetNextMDIChildWnd();
}
}
//-----------------------------------------------------------------
// This function counts the number of CMDIChildWnd objects
// currently maintained by the MDIClient.
//-----------------------------------------------------------------
int CMainFrame::GetCountCMDIChildWnds()
{
int count = 0;
CMDIChildWnd* pChild = GetNextMDIChildWnd();
while (pChild)
{
count++;
pChild = GetNextMDIChildWnd();
}
return count;
}
问】 我想实现一个功能,就是检测一个目录或文件,看它是否存在,如果不存在就创建这个目录或文件。
答】
可以用Win32文件查找来查找文件或者文件夹是否存在,也可以用PathFileExists来判断。GetFileAttributes和PathIsDirectory可以用于判断文件是否是目录。创建文件可以用CreateDirectory或者MakeSureDirectoryPathExists。
bool FileExists(CString FileName)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
bool FindFlag=false;
hFind = FindFirstFile(FileName , &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
FindFlag= false;
}
else
{
FindFlag=true;
}
FindClose(hFind);
return FindFlag;
}
DWORD dwFlag = GetFileAttributes(pathname);
if ( 0xFFFFFFFF == dwFlag ) 不存在;
if ( FILE_ATTRIBUTE_DIRECTORY & dwFlag ) 是文件夹
else 是文件
问】 播放MP3
答】system("start \"mp3\" /B \"D:\\一剪梅.mp3 \"");
问】 如何使CTreeCtrl的节点即使没有子节点也显示+号?
答】http://www.microsoft.com/msj/archive/S563.aspx
问】怎样把某项菜单置灰?
答】
1
menu.EnableMenuItem(ID_VIEW_MYCONTROL_BAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2
用OnUpdataCommandUI( CCmdUI* pCmdUI)
pCmdUI->Enable( FALSE );
------
问】如何动态改变菜单?
答】
1
CMenu cMenu;
//调用新的以IDR_NEWMENU表示的菜单资源;
cMenu.LoadMenu(IDR_NEWMENU);
//将cMenu设置为当前菜单;
SetMenu(&cMenu);
//释放菜单句柄
cMenu.Detach();
//重画菜单条;
DrawMenuBar();
//重新绘制窗口区域;
RecalcLayout(TRUE);
2
//装载菜单资源:
m_Menu.LoadMenu(IDR_MENU_REPORT);
//销毁原菜单:
this->SetMenu(NULL);
::DestroyMenu(this->m_hMenuShared); //m_hMenuShared指框架主菜单 m_hMenuDefault视图菜单
//设置新的菜单:
this->SetMenu(&m_Menu);
this->m_hMenuShared = m_Menu.GetSafeHmenu();
//重画菜单条
this->DrawMenuBar();
问】当程序窗口隐藏时的弹出菜单问题?
答】
如果使用TrackPopupMenu并且如果不加SetForegroundWindow()的话,菜单就会一直显示着,除非你选择了其中某一个菜单项。所以在使用TrackPopupMenu()的时候前面一定要加句SetForegroundWindow()。
问】当单击最小化菜单时,如何获取他的消息
答】
在OnSize函数里拦截消息进行判断
void C****::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType,cx,cy);
if (nType == SIZE_MINIMIZED)
{
AfxMessageBox("minbox");
}
}
问】在TreeView的WM_CONTEXTMENU里用TrackPopupMenu函数不能显示右键菜单,双击右键却正常显示?
答】
1
在右键之后,发送消息看看。在RichEditView里碰到类似的问题。
void CAdminView::OnRButtonDown(UINT nFlags, CPoint pt)
{
CRichEditView::OnRButtonDown(nFlags, pt);
ClientToScreen (&pt);
SendMessage(WM_CONTEXTMENU,(WPARAM)m_hWnd,MAKELPARAM(pt.x, pt.y));
}
2
把WM_RBUTTONDOWN消息屏蔽了
void Cxxx::OnRButtonDown(...)
{
// don't call the base OnRButtonDown
}
问】如何发消息使某个菜单响应?
答】
::SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(ID_MENUITEM, 0), NULL);
其中ID_MENUITEM是菜单项的ID,而hwnd是View或FrameWnd的句柄(无论消息发给View还是FrameWnd,都将按照View、Document、FrameWnd、theApp的顺序进行,当然只是针对WM_COMMAND消息),当然,直接发给消息响应函数所在的窗口(如果它是一个窗口的话)那是最好不过的了。
问】如何用windowsAPI制作多级菜单?
答】
CMenu MainMenu;
CMenu SonMenu;
MainMenu.CreatePopupMenu();
MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 42, "Apples");
MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Pears");
MainMenu.AppendMenu(MF_STRING | MF_ENABLED, 43, "Grapes");
SonMenu.CreatePopupMenu();
SonMenu.AppendMenu(MF_STRING | MF_ENABLED, 40, "Mangos");
SonMenu.AppendMenu(MF_STRING | MF_ENABLED, 41, "Tomatoes");
MainMenu.AppendMenu(MF_STRING | MF_POPUP | MF_ENABLED,
(UINT)MiscFruitMenu.m_hMenu, "Son Menu");
MainMenu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this, NULL);
问】怎样加载DLL中的菜单资源啊?
答】
按照以下步骤就可以:
1
资源DLL的建立,新建一个MFC Extension DLL,删除向导生成的资源文件,把你的程序的资源文件加入工程并且编译。
参考知识库文章 Q198846 HOWTO: Create Localized Resource DLLs for MFC Application
MFC技术文章TN057: Localization of MFC Components
注意在PROJECT SETTING / LINK / PROJECT OPTION 中添加 /NOENTRY
具体说明看MSDN,还有别忘了在EXE中包含RESOURCE.H
2
EXE的测试:
BOOL CTestResOnlyDLLDlg::OnInitDialog()
{
m_hInst = 0;
m_hInst = LoadLibrary("ResOnlyDll.dll");
ASSERT(m_hInst);
m_hMenu = ::LoadMenu(m_hInst,MAKEINTRESOURCE(IDR_MENU_DLL));
ASSERT(m_hMenu);
m_cMenu.Attach(m_hMenu);
SetMenu(&m_cMenu);
...
return TRUE;
}
void CTestResOnlyDLLDlg::OnDestroy()
{
CDialog::OnDestroy();
FreeLibrary(m_hInst);
}
菜单的消息映射跟原来一样。
问】如何确定视图右键菜单的位置?
答】
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
m_list.ClientToScreen(&point);
CMenu*pPopMenu=new CMenu;
pPopMenu->LoadMenu(IDR_MENU1);
CMenu*pFileMenu=pPopMenu->GetSubMenu(0);
pFileMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);
delete pPopMenu;
问】如何屏蔽ie菜单中的查看-->源文件项?
答】
1
http://dev.csdn.net/article/19/19627.shtm
2
M$抠出的一段代码
==
HRESULT CClientView::OnShowContextMenu(DWORD dwID, LPPOINT ppt, LPUNKNOWN pcmdTarget, LPDISPATCH pdispObject)
{
#define IDR_BROWSE_CONTEXT_MENU 24641
#define IDR_FORM_CONTEXT_MENU 24640
#define SHDVID_GETMIMECSETMENU 27
#define SHDVID_ADDMENUEXTENSIONS 53
HRESULT hr;
HINSTANCE hinstSHDOCLC;
HWND hwnd;
HMENU hMenu;
CComPtr<IOleCommandTarget> spCT;
CComPtr<IOleWindow> spWnd;
MENUITEMINFO mii={0};
CComVariant var, var1, var2;
hr = pcmdTarget->QueryInterface(IID_IOleCommandTarget, (void**)&spCT);
hr = pcmdTarget->QueryInterface(IID_IOleWindow, (void**)&spWnd);
hr = spWnd->GetWindow(&hwnd);
hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL"));
if (hinstSHDOCLC == NULL)
{
// 载入模块错误 -- 尽可能安全地失败
return S_FALSE;
}
hMenu=LoadMenu(hinstSHDOCLC, MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));
hMenu=GetSubMenu(hMenu,dwID);
//获得语言子菜单
hr = spCT->Exec(&CGID_ShellDocView, SHDVID_GETMIMECSETMENU, 0, NULL, &var);
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = (HMENU) var.byref;
//加入语言子菜单到编码上下文菜单
SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &mii);
//插入来自注册表的快捷菜单扩展
V_VT(&var1) = VT_INT_PTR;
V_BYREF(&var1) = hMenu;
V_VT(&var2) = VT_I4;
V_I4(&var2) = dwID;
hr = spCT->Exec(&CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &var1, &var2);
//删除查看源代码
DeleteMenu(hMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);
//显示快捷菜单
int iSelection = ::TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ppt->x,
ppt->y,
0,
hwnd,
(RECT*)NULL);
//发送选定的快捷菜单项目指令到外壳
LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
FreeLibrary(hinstSHDOCLC);
return S_OK;
}
问】如何在treeview里实现在节点上点击右键出现右键菜单?
答】
响应WM_CONTEXT消息
====>CTreeCtrl::HitTest可以得到结点
=====>生成一个CMenu对象
=====>CMenu::LoadMenu
====>CMenu::TrackPopupMenu来显示弹出菜单.
点击后,====>进行菜单项的处理.
void CLeftView::OnRclick(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
CPoint pt ;//= point;
GetCursorPos(&pt);
ScreenToClient(&pt);
UINT uFlags;
HTREEITEM hItem = GetTreeCtrl().HitTest(pt, &uFlags);
if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
{
GetTreeCtrl().SetFocus();
GetTreeCtrl().Select(hItem,TVGN_CARET);
CWnd* mwnd = GetFocus();
CMenu PopMenu;
PopMenu.LoadMenu(IDR_POP_ITEM);
PopMenu.GetSubMenu(0)-TrackPopupMenu
(TPM_LEFTALIGN|TPM_RIGHTBUTTON,pt.x,pt.y,this);
}
}
同时如果是根结点的话,你可以用CTreeCtrl::GetRootItem()得到根结点,然后再判断CTreeCtrl::HitTest得到的结点是否是根结点,如果是判断一个结点是否还有子结点可以用CTreeCtrl::ItemHasChildren(hItem)
问】当MDI程序启动时,子窗口最大化显示?
答】重载ActivateFrame函数:
void CChildFrame::ActivateFrame(int nCmdShow)
{
nCmdShow = SW_MAXIMIZE;
CMDIChildWnd::ActivateFrame(nCmdShow);
}
问】讲一下NetBios究竟有什么用
答】NetBIOS网络协议对于很多读者来说可能比较陌生,但其实它是由IBM开发的一个很古老的协议,当年在LAN上也风光一时。说它老,其实也不过10年光景,IT业的发展实在是太快。由于NetBIOS不具备路由功能,也就是说它的数据包无法跨网段传输,因此在广域网、城域网大行其道的今天,它已退居配角。如果你有心的话,能够发现在Window95/98的网络协议中仍然保留着NetBIOS,不过它已经改名叫NetBEUI
(NetBIOS扩展用户接口),是NetBIOS的Microsoft改进版。另外在TCP/IP以及IPX/SPX协议中,也依然保留了对NetBIOS的支持,只要查看网络协议属性中的高级,就能看到启用NetBIOS的选项。之所以这样是有原因的。NetBIOS协议短小精悍,非常适用于小型局域网,特别是一些对实时性要求较高的网络境。NetBIOS的广播功能由于有开发使用方便、系统开销小的优点,所以在很多场合仍然被大量使用
相关推荐

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值