最近一直在研究如何将CAD嵌入Excel中,并可以随Excel主程序尺寸变化而自适应。本来要模仿E算量的效果。 最新的方案:将CAD窗口嵌入外部窗体,动态设置该窗体与Excel主窗体的位置关系。效果如下: 着重说原理和思路,代码是次要的。本文所说效果是在vsto开发中实现的,使用的是VB.net语言。 大致分为这几个难点:
xldeskHwnd = FindWindowEx(xlhwnd, 0&, "XLDESK", vbNullString) api函数FindWindow可以根据指定的类名和窗口标题名称获得顶层窗口的句柄。 FindWindowEx函数可以根据主窗口句柄,找到子窗口句柄。一般两个API函数结合,获取主窗口内部某个窗口的句柄。 有了窗口句柄,可以做很多事情。
Excel主窗口(类名:XLMAIN) └────Excel工作区窗口(类名:XLDESK) └────Excel工作簿窗口(Excel7)
SetParent是一个API函数,它的作用是为一个程序窗口指定一个新的父窗体。(父窗体严格来说是容器)。也就是把一个物体转到另一个物体上去 ,Setparent 的用法相当简单 。 程序中,将CAD程序设置为窗体的子程序: SetParent(lHwnd, Me.Handle) 'lHwnd为CAD窗口的句柄,该句作用是设置本窗体为CAD的母窗体 只要获得窗口句柄,我们还可以将很多窗口嵌入Excel:
MoveWindow(ByVal hwnd As Integer, ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal bRepaint As Integer) As Integer 参数: x:指定窗口的新位置的左边界。 Y:指定窗口的新位置的顶部边界。 nWidth:指定窗口的新的宽度。 nHaight:指定窗口的新的高度。
Public Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Integer, ByRef lpRect As RECT) As Integer Public Structure RECT Dim Left As Integer Dim Top As Integer Dim Right As Integer Dim Bottom As Integer End Structure
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load 'SetHook() xlhwnd = xlapp.Hwnd xldeskHwnd = FindWindowEx(xlhwnd, 0&, "XLDESK", vbNullString) GetWindowRect(xldeskHwnd, r) '保存窗体原来的位置及大小到变量r EXCEL7Hwnd = FindWindowEx(xldeskHwnd, 0&, "EXCEL7", vbNullString) SetParent(Me.Handle, xldeskHwnd) '设置xldesk窗体为母窗体 '------------------------设置窗体按钮panel位置--------------------------- '按钮位置 Me.Panel1.Dock = DockStyle.Right Me.Panel1.Left = Me.Left + Me.Width - 50 Me.Panel1.Width = 35 MoveWindow(Me.Handle, 0, 0, r.Width / 2, r.Height, True) '移动窗体位置 '--------------------------打开CAD-------------------------------------- Try app = GetObject(, "AutoCAD.Application") app.Visible = True Catch ex As Exception Try app = CreateObject("AutoCAD.Application") Catch dd As Exception MsgBox("不能启动AutoCAD,是否没有安装?") End Try End Try '---------------------------------------------------------------- app.Visible = True '显示cad程序界面 lHwnd = GetParent(GetParent(app.ActiveDocument.HWND)) '获得CAD窗体的句柄 If lHwnd = 0 Then Exit Sub '如果没有获取大句柄,直接退出 '------------------------设置Excel7位置尺寸--------------------------- 'Excel7位置尺寸 MoveWindow(EXCEL7Hwnd, r.Width / 2, 0, r.Width / 2, r.Height, True) '---------------------------------------------------------------------------- SetParent(lHwnd, Me.Handle) '设置本窗体为CAD的母窗体 MoveWindow(lHwnd, 0, 0, Me.Width - 50, Me.Height, True) End Sub
Private Sub Form2_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize xlhwnd = xlapp.Hwnd xldeskHwnd = FindWindowEx(xlhwnd, 0&, "XLDESK", vbNullString) GetWindowRect(xldeskHwnd, r) '保存窗体原来的位置及大小到变量r EXCEL7Hwnd = FindWindowEx(xldeskHwnd, 0&, "EXCEL7", vbNullString) MoveWindow(lHwnd, 0, 0, Me.Width - 50, Me.Height, True) 'Excel7位置尺寸 MoveWindow(EXCEL7Hwnd, Me.Width, 0, r.Width - Me.Width, r.Height, True) End Sub
Private Sub Form2_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing 'UnHook() SetParent(lHwnd, 0) app.WindowState = AutoCAD.AcWindowState.acNorm '//EXCEL7窗口恢复 xlhwnd = xlapp.Hwnd xldeskHwnd = FindWindowEx(xlhwnd, 0&, "XLDESK", vbNullString) GetWindowRect(xldeskHwnd, r) '保存窗体原来的位置及大小到变量r EXCEL7Hwnd = FindWindowEx(xldeskHwnd, 0&, "EXCEL7", vbNullString) MoveWindow(EXCEL7Hwnd, r.Left, 0, r.Width, r.Height, True) End Sub
这部分完美的做法应该是利用HOOK技术,监视Excel主程序窗口的变化。目前能力受限,由于目前是自用,也能满足自身需求,优化暂时搁置。 Private Sub Application_WindowResize(Wb As Workbook, Wn As Window) Handles Application.WindowResize xlhwnd = xlapp.Hwnd xldeskHwnd = FindWindowEx(xlhwnd, 0&, "XLDESK", vbNullString) '获取xldesk窗口句柄 EXCEL7Hwnd = FindWindowEx(xldeskHwnd, 0&, "EXCEL7", vbNullString) '获取EXCEL7窗口句柄 formhandle = FindWindowEx(xldeskHwnd, 0&, vbNullString, "CAD窗口") '获取标题名为CAD窗口的窗体句柄 If formhandle = 0 Then Exit Sub '获取不到句柄,不做调整 GetWindowRect(xldeskHwnd, r) '保存xldesk的位置及大小到变量r MoveWindow(formhandle, 0, 0, r.Width / 2, r.Height, True) '实时移动窗体位置 GetWindowRect(formhandle, cadrect) '保存修改过的cad窗体尺寸到=及位置到变量cadrect,为了下一步设置Excel7窗口的大小 MoveWindow(EXCEL7Hwnd, cadrect.Width, 0, r.Width - cadrect.Width, r.Height, True) End Sub ▌写在后面 最初框架已经形成,下一步就是慢慢填充各种算量小功能: 有了上面的一些技术知识,可以初步做出来一个简易聚光灯。 思路是:叠加半透明异形窗体在Excel工作区,利用SelectionChange事件动态调整窗口十字中心的位置。 留待以后研究。 |
|