VC小知识总结(三)-------经典

作者在 2009-03-09 09:18:44 发布以下内容
(31)DLL中的模板成员函数?

在一个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.否则会出错。

VC++ | 阅读 1707 次
文章评论,共0条
游客请输入验证码
浏览195166次