您的位置:网站首页 > CAD新闻

Hook技术在CAD中的使用方法

时间:2012-03-02 10:23:44 来源:未知

本实例主要是讲Hook技术在CAD中的使用方法。
Hook技术就是所谓钩子技术,在CAD的二次开发过程中,有很多的情况,是需要使用钩子技术的(尽管CAD已经提供了强大的反应器技术),由于CAD也是基于MFC开发的应用程序,我们也可以像HOOK其它应用程序一样的方法来HOOKCAD,但有些时候,一些消息不知道怎么回事,会HOOK不到。比如:按下SHIFT键。 不管怎么样,CAD还是把HOOKCAD消息的处理方法封装了一下。很好用,主要有以下几种:

// Define callback function for apps that want windows messages
typedef void (* AcedWatchWinMsgFn)(const MSG*); //定义监视消息的函数指针
typedef BOOL (* AcedFilterWinMsgFn)(MSG*);   //定义过滤消息的函数指针
typedef void (* AcedOnIdleMsgFn) ();     //定义监视CAD空闲时间的函数指针

// Windows messages hooks
/* Register a filter message hook into AutoCAD's Windows message loop.
* The message passed to your application can be changed and can be blocked out.
* If the function returns TRUE, the message WON'T be passed to other hook
* functions or AutoCAD at all. The message is terminated.
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*/
以上的意思大概是,在CAD的WINDOWS 消息循环中定义一个hook,你可以在其中处理这个消息,这个处理函数是必须有返回值的,返回TRUE,这个消息不会传递给其它的HOOK和CAD了,这个消息就中止了,如果返回FALSE,这个消息将可以被任何其它的HOOK和CAD处理。
不过个人做了一个实验,返回TRUE时,CAD好像还是可以对这个消息进行一个处理。这个地方还有待研究。
BOOL acedRegisterFilterWinMsg(const AcedFilterWinMsgFn pfn);

/* acedRemoveFilterWinMsg
* Takes a message hook function pointer and remove it
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*/
很简单,移除上面注册的过滤函数
BOOL acedRemoveFilterWinMsg(const AcedFilterWinMsgFn pfn);

/* acedRegisterWatchWinMsg
* Register a hook function into AutoCAD message loop.
* The function can only look up AutoCAD's Windows message.
* It can't change or block message.
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*/
以上的意思大概是,在CAD的WINDOWS 消息循环中定义一个hook,你可以在其中查看CAD的任何消息,但不能中止其消息的传递,当然,你可以监控到一些消息后,做一些你自己要做的事,但不会中断消息的传递。
BOOL acedRegisterWatchWinMsg(const AcedWatchWinMsgFn pfn);

/* acedRemoveWatchWinMsg
* Takes a message hook function pointer and remove it
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*
*/
很简单,移除上面注册的监控函数
BOOL acedRemoveWatchWinMsg(const AcedWatchWinMsgFn pfn);

/* acedRegisterOnIdleWinMsg
* Register a hook function to be notified when AutoCAD is on idle
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*/
以上的意思大概是,在CAD的WINDOWS 消息循环中定义一个hook,当CAD的空闲时间时,就会激活这个定义的HOOK,然后你就可以做一些处理了。
BOOL acedRegisterOnIdleWinMsg(const AcedOnIdleMsgFn pfn);

/* acedRemoveOnIdleWinMsg
* Takes a message on idle hook function pointer and remove it
* Returns TRUE if successfully registers the hook. Otherwise FALSE.
*
*/
简单,移除上面注册的监控空闲时间函数
BOOL acedRemoveOnIdleWinMsg(const AcedOnIdleMsgFn pfn);


在CAD二次开发中,HOOK技术应该还是很有用的,比如,最近,我在做一个在CAD中定义右键菜单的功能。以前已经做过一个右键菜单,用CONTEXTMENU,但不能把CAD本身的菜单给干掉,早几天看到BENTLY公司在CAD平台上做的开发,他们的右键菜单完全没有CAD的影子,所以,我下定决心,要尝试着把CAD的右键给干掉,有人说,可以自己定义CUI文件搞定,但我们的软件是要兼容低版本的CAD,所以不能用这种方法,想了想,HOOK的方法可能适合,自己试了试,感觉还行。以下是自己写的核心代码。
//pick the current selectset
BOOL HasEntityBeSelected()
{
// 如果AutoCAD关闭,则不执行任何任务。
//
if (!acdbHostApplicationServices()->workingDatabase())
   return FALSE;

// 取得刚打开的实体
//
ads_name sset;
int err = acedSSGet(_T("I"), NULL, NULL, NULL, sset);
if (err != RTNORM)
{
   /*acutPrintf(_T("n获取选择集错误n"));*/
   return FALSE;
}
/*actrTransactionManager->startTransaction();*/
long length;
acedSSLength(sset, &length);
acedSSFree(sset);
if( length > 0 )
{
   return TRUE;
}
else
{
   return FALSE;
}
}


//catch the message
int CatchRClick(MSG* msg)
{
CView* pView = acedGetAcadDwgView();//获得程序主框架指针
HWND hActiveWnd = ::GetActiveWindow();
BOOL bInView = TRUE;
CPoint pt;
::GetCursorPos(&pt);
CRect rect;
::GetWindowRect( hActiveWnd , rect );
if( pt.x > rect.left &&
   pt.x < rect.right &&
   pt.y > rect.top &&
   pt.y < rect.bottom )
{
   bInView = FALSE;
}

CWnd* pMainWnd = acedGetAcadWinApp()->m_pMainWnd;
HWND hMainWnd = pMainWnd->m_hWnd;

if( hActiveWnd && hActiveWnd == hMainWnd )
{
   bInView = TRUE;
}

if( msg->message == WM_RBUTTONDOWN && bInView )
{
   CMenu* pMenu = NULL;
   if( HasEntityBeSelected() )
   {
    if( pObject )
    {
     pMenu = pObject->GetMainMenu(); //弹出选中了实体的右键菜单
    }
   }
   else
   {
    if( pDefault )
    {
     pMenu = pObject->GetMainMenu();//弹出未选中了实体的右键菜单
    }
   }
   CPoint pt;
   ::GetCursorPos(&pt);
   CRect rect;
   ::GetWindowRect(pView ->m_hWnd, rect );
   if( pt.x > rect.left &&
    pt.x < rect.right &&
    pt.y > rect.top &&
    pt.y < rect.bottom )
   {
    pMenu->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y, pView);//单击右键菜单时弹出菜单指针
    return 1;
   }
   else
   {
    return 0;
   }
}
else
{
   return 0;
}
}

// Init this application. Register your
// commands, reactors...
void InitApplication(void *pkt)
{
// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_INIT
//}}AFX_ARX_INIT

// TODO: add your initialization functions

pDefault = new DefaultContextMenu(_hdllInstance);
pObject = new ObjectContextMenu(_hdllInstance);

acedRegisterFilterWinMsg( CatchRClick );
}
// Unload this application. Unregister all objects
// registered in InitApplication.
void UnloadApplication()
{
// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_EXIT
//}}AFX_ARX_EXIT

// TODO: clean up your application
If( pDefault )
   delete pDefault;
if( pObject )
   delete pObject;
acedRegisterFilterWinMsg( CatchRClick );
}