在一个DLL中,我在自己创建的类中使用了模板成员函数来代替预处理宏.但出现以下错误:
error C2664: 'double Data::extract(double &)' : cannot convert parameter 1
from 'class CArray' to 'double &'
为什么在匹配模板定义时它要寻找一个DOUBLE参数?
我觉得你可能是在表达成员函数(内联)时出现了问题,请参照下面的示例:
class AFX_EXT_CLASS Data : public CObject //This is not a template
{
public:
Data();
Data(BYTE * buffer,int size);
template
Data(const CArray& array);
template
CArray& extract(CArray& array)
{
CArchive ar(&buffer, CArchive::store);
ar >> array;
};
double extract(double&);
(...)
private:
CMemFile buffer;
}
(32)CFormView中的上下文帮助?
我想在基于CFormView类的SDI应用程序中加入真正的上下文帮助,但没有成功.
你应该重载CMyFormView类的OnHelpHitTest函数:
LRESULT CMyFormView::OnHelpHitTest(WPARAM, LPARAM lParam)
{
LRESULT lResult = (LRESULT)0x00;
CWnd* pWndChild = ChildWindowFromPoint(CPoint(lParam),
CWP_ALL|CWP_SKIPINVISIBLE);
if (pWndChild && ::IsWindow(pWndChild->m_hWnd))
{
lResult = ::GetWindowLong(pWndChild->m_hWnd, GWL_ID);
if (lResult)
lResult += HID_BASE_COMMAND;
}
if (lResult == (LRESULT)0x00)
lResult = ::GetWindowLong(m_hWnd, GWL_ID) + HID_BASE_RESOURCE;
return lResult;
}
然后你就可以使用平时用的帮助文件了,但你要保证有正确的前缀,请参照
TN028:Context-Sensitive Help Support.
例如:
ID_SOME_MENU_ITEM_OR_COMMAND_BUTTON
IDR_SOME_WINDOW_OR_DIALOG
IDP_PROMPT
IDW_CONTROL_THAT_IS_NOT_A_COMAND_BUTTON
你要确认你所使用的控件的ID包含在文件resource.hm中.
(33)CArchive类的WriteObject函数问题?
谁知道在使用CArchive类的WriteObject函数时,如何避免将类名写入文件吗?
WriteObject函数不仅写入了类名,而且还写入PID(请查看TN02),如果你只想写进一个文本文件,并且你也想用串行化,你可以使用文件指针(用GetFile)来存储字符串.或者,你可以使用CFILE类来处理这个问题,如果是文本文件,你也可以用CStdioFile类.
(34)RegisterWindowMessage中的BroadcastSystemMessage如何处理?
我想用BroadcastSystemMessage来在两个进程之间通讯,我从一个进程发送了一个用RegisterWindowMessage注册过的消息,但在目的进程中却没有收到该消息.
我认为你应该在两个进程的最高级窗口中都注册该消息.请看下例:
static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
BEGIN_MESSAGE_MAP( Gui_Top_Level_MainFrame, Gui_MainFrame )
ON_REGISTERED_MESSAGE( sBroadcastCommand, onBroadcastCommand )
END_MESSAGE_MAP()
LRESULT Gui_MainFrame :: onBroadcastCommand( UINT aMsg, LPARAM lParam )
{
your code...
}
然后发送进行应该包含:
While the sending process would contain:
static UINT sBroadcastCommand = ::RegisterWindowMessage( _T("BroadcastCommand"));
void Someclass :: someMethod( void )
{
::PostMessage( (HWND)HWND_BROADCAST,
sBroadcastCommand, 0,
yourMessageId );
}
(35)CListCtrl中选择变化时如何获得通知?
我在Report View中使用了一个CListCtrl(自绘制类型),我想知道什么时候选择项发生了改变.
在选择项变化时,可以使用按钮有效或失效,按如下操作:
加入LVN_ITEMCHANGED消息处理.
void CYourClassNameHere::OnItemchangedEventList(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
*pResult = 0;
if (pNMListView->uChanged == LVIF_STATE)
{
if (pNMListView->uNewState)
GetDlgItem(IDC_DELETE)->EnableWindow(TRUE);
else
GetDlgItem(IDC_DELETE)->EnableWindow(FALSE);
}
}
(36)如何向ATL-COM对象传送一个数组?
我想创建一个函数来向ATL-COM对象传送数组.
如下代码的方法用于ACTIVEX中,可能对ATL-COM也有启发吧.
CoInitialize(NULL);
CLSID m_clsid;
USES_CONVERSION;
::CLSIDFromString(T2OLE("ROUNDANALOG.RoundAnlgAARCtrl.1"), &m_clsid);
IDispatch FAR* pObj = (IDispatch FAR*)NULL;
CString str = "UpdateControl";
BSTR bstr = str.AllocSysString();
HRESULT hr = CoCreateInstance(m_clsid, NULL, CLSCTX_ALL, IID_IDispatch,
(void**)&pObj);
SafeArrayAccessData(psa, (void**)&bstrArray);
bstrArray[0] = str.AllocSysString();
bstrArray[1] = str.AllocSysString();
SafeArrayUnaccessData(psa);
VARIANTARG* pvars = new VARIANTARG[1];
VariantInit(&pvars[0]);
pvars[0].vt = VT_ARRAY|VT_BYREF|VT_BSTR;
pvars[0].pparray = &psa;
DISPID dispid;
hr = pObj->GetIDsOfNames(IID_NULL, &bstr, 1,LOCALE_USER_DEFAULT, &dispid);
DISPPARAMS disp = {pvars, &dispid, 1,1};
hr = pObj->Invoke(dispid, IID_NULL,
LOCALE_USER_DEFAULT,DISPATCH_PROPERTYPUT,&disp,NULL, NULL, NULL);
delete[] pvars;
pObj->Release();
CoUninitialize();
在你的控制中建立如下并变量参考:
void CRoundAnlgAARCtrl::SaveFunc(const VARIANT FAR& var)
{
// TOD Add your dispatch handler code here
ASSERT(var.vt == VT_ARRAY | VT_BYREF | VT_BSTR);
SAFEARRAY* psa = *var.pparray;
}
(37)如何选择CTreeCtrl中的节点文本进行编辑?
在向CTreeCtrl中加入一项后,有什么方法可以编辑该节点的文本呢?
首先设置你的CcompTreeCtrl具有TVS_EDITLABELS属性.在设计时用控件属性来设置在运行时用GetStyle()/SetStyle()成员函数来设置.然后请看下述代码:
HTREEITEM CCompTreeCtrl::AddSet()
{
static int setCnt =3D 1;
HTREEITEM hItem;
CString csSet;
//create text for new note: New Set 1, New Set 2 ...
csSet.Format( _T( "New Set %d" ), setCnt++ );
hItem =3D InsertItem( csSet, IMG_CLOSEDFOLDER, IMG_CLOSEDFOLDER );
if( hItem !=3D NULL )
EditLabel( hItem );
return hItem;
}
(38)如何改变默认的光标形状?
我试着将光标改变为其它的形状和颜色,但却没有变化.
在对话框/窗口/你需要的地方加上对WM_SETCURSOR消息的处理.
BOOL MyDialog::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TOD Add your message handler code here and/or call default
::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR));
return TRUE;
//return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
你没有成功的原因是因为窗口类光标风格不能为NULL.
(39)如何用键盘滚动分割的视口?
我的问题是当我用鼠标滚动分割窗口时,视口滚动都很正常,但用键盘时,却什么也没有发生.
在你的视图继承类中加入如下两个函数,假定该类为CScrollerView:
void CScrollerView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
BOOL processed;
for (unsigned int i=0;i< nRepCnt&&processed;i++)
processed=KeyScroll(nChar);
if (!processed)
CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}
BOOL CScrollerView::KeyScroll(UINT nChar)
{
switch (nChar)
{
case VK_UP:
OnVScroll(SB_LINEUP,0,NULL);
break;
case VK_DOWN:
OnVScroll(SB_LINEDOWN,0,NULL);
break;
case VK_LEFT:
OnHScroll(SB_LINELEFT,0,NULL);
break;
case VK_RIGHT:
OnHScroll(SB_LINERIGHT,0,NULL);
break;
case VK_HOME:
OnHScroll(SB_LEFT,0,NULL);
break;
case VK_END:
OnHScroll(SB_RIGHT,0,NULL);
break;
case VK_PRIOR:
OnVScroll(SB_PAGEUP,0,NULL);
break;
case VK_NEXT:
OnVScroll(SB_PAGEDOWN,0,NULL);
break;
default:
return FALSE; // not for us
// and let the default class
// process it.
}
return TRUE;
}
(40)如何在线程中处理状态条?
在我的应用程序CWnd的继承中有指针指向状态条,用pStatusBar->SetPaneText(0,status,TRUE)在状态条上显示一些文本都很正常.但在第二个线程中调用该函数却不行,出现hwnd警告.
当你传送一个CWnd的指针到另外一个线程时,m_hWnd将为空.我的办法是用PostThreadMessage传送消息到状态条的父类,让它对状态条进行处理.
(41)如何阻止WINDOWS关闭?
我有一个应用程序会不停地工作.当该程序正常运行时,该如何避免用户关掉系统?是不是该用WM_QUERYENDSESSION.
是的,在你的主框架窗口类中使用.
// in the class header
afx_msg BOOL OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason );
// in the Message Map
ON_MESSAGE( WM_QUERYENDSESSION, OnQueryEndSession )
// in the class body
BOOL CMainFrame::OnQueryEndSession( WPARAM wReserved, LPARAM lEndReason )
{
if( lEndReason =3D=3D ENDSESSION_LOGOFF ) {
// user is logging off
else
// Windows is going down
return( bCanExit );
}
(42)如何使一个按钮Disable?
我使用下面代码来Disable一个为ID_BUTTON的按钮,为什么会没有变化.
GetDlgItem(IDC_BUTTON)->EnableWindow(FALSE);
CWnd类中的EnableWindow函数用来Enable或Disable一个窗口类的对象,因为CButton类继承于类CWnd,所以你可以使用来操作一个按钮.Enable一个基于窗口类的对象可以用以下代码:
pWnd->EnableWindow(TRUE);
Disable一个对象可用
pWnd->EnableWindow(FALSE);
其中pWnd为一个指向窗口对象的指针VC++中消息WM_ENABLE告诉窗口它正在Disable或Enable,但它并不能使一个窗口Enable或Disable.
(43)怎样从MFC扩展动态链结库(DLL)中显示一个对话框?
我在过去的几天中试着在DLL中定义的函数中显示一个对话框,可是已经在DLL中定义好的对话框资源,在常规DLL调用时,我可以正常的显示出来,为什么在扩展DLL中同样的资源我却不能显示.
当你在DLL中使用资源时,有些小细节需要注意,首先,在DLL运行时,必须保存DLL的实例,可以通过AfxInitExtensionModule
static AFX_EXTENSION_MODULE extensionDLL;
extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(extensionDLL, hInstance))
return false;
}
return(true);
}
然后,每次使用DLL资源时,你必须改变资源的句柄,使其指向DLL,并保存exe的资源,以便以后正确恢复
void get_DLL_resource(void)
{
/* this function changes the resource handle to that of the DLL */
//这个函数改变资源句柄使其指向DLL
if (resource_counter == 0)
{
save_hInstance = AfxGetResourceHandle();
AfxSetResourceHandle(extensionDLL.hModule);
}
resource_counter++;
}
接着你需要其它函数来恢复资源句柄
void reset_DLL_resource(void)
{
/* this function restores the resource handle set by
'get_DLL_resource()' */
if (resource_counter > 0)
resource_counter--;
if (resource_counter == 0)
AfxSetResourceHandle(save_hInstance);
}
接下来一点非常重要,只要有可能就必须恢复资源句柄,否则,你将会遇到许多问题.原因是可执行文件必须重画工具条等等,比如说,如果用户移动DLL的对话框,如果资源句柄仍然为DLL的资源,程序就崩溃了,我发现最好恢复句柄的时机在对话框的OnInitDialog()中,这时对话框的模板等已经读出了.
(44)想隐藏用户界面怎么办?
我编了一个小巧而有趣的工具,当用户使用时我不想让它显示出任何用户界面。听听各位有办法可将视关闭。
你可以注册一个新的窗口类型,它拥有除了WS_VISBLE属性外的任何属性,类似CFrameWnd,在PreCreateWindow方法中实现。另外,你能在OnCreate方法中通过设置m_nCmdShow为SW_HIDE来实现,具体方法如下:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// hide our app
AfxGetApp()->m_nCmdShow = SW_HIDE;
return 0;
}
(45)如何实现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.否则会出错。