LISP+DWX 之一:Windows API 调用示例
本帖最后由 yxp 于 2018-5-12 14:30 编辑利用 DynamicWrapperX 插件,可以在 LISP 里使用系统 DLL,Windows 系统自带了大量的 MFC 基础类库,每个库文件又包含了很多函数,据说连微软自己都不知道有多少 API 函数。
下面代码将演示用 lisp 控制 API 后台打开一个记事本,激活记事本窗口,模拟按键输出字符。
;;by:yxp 2018/04/12
;;Windows API 在 lisp 中应用示例 2
;;演示: 打开一个记事本,使记事本窗口在最前,并向记事本输出一段文字
(defun c:outputtext( / *CAD* *dwg* hCAD DWX jsb)
;;变量初始化
(setq *CAD* (vlax-get-acad-object) ;;当前打开的 CAD 对象
*dwg* (vla-get-ActiveDocument *CAD*) ;;当前激活的 dwg 文档对象
hCAD (vla-get-hwnd *CAD*) ;;顶层 CAD 对象句柄
hdwg (vla-get-hwnd *dwg*) ;;当前 dwg 对象句柄
DWX (vlax-get-or-create-object "DynamicWrapperX")) ;; 创建一个 DWX 对象
;;Windows API 函数声明
(vlax-invoke DWX 'Register "shell32.dll" "ShellExecuteW" "i=hwwwwl" "r=m")
(vlax-invoke DWX 'Register "user32" "SetWindowTextW" "i=hw" "r=m")
(vlax-invoke DWX 'Register "user32" "GetKeyState" "i=n" "r=l")
(vlax-invoke DWX 'Register "user32" "keybd_event" "i=llll" "r=m")
(vlax-invoke DWX 'Register "user32" "SetWindowPos" "i=hmmmmmm" "r=m")
(vlax-invoke DWX 'Register "kernel32" "Beep" "i=mm" "r=m")
(vlax-invoke DWX 'Register "kernel32" "Sleep" "i=m")
;;后台启动一个记事本,但不显示,用参数 0
;;注意,记事本和 CAD 是兄弟关系,不是父子关系
(vlax-invoke DWX 'ShellExecuteW hCAD "open" "notepad" "" "" 0)
(setq jsb (get-fun-hand hCAD "*记事本"));;获取记事本进程的句柄
(if (= jsb 0) (princ "\n记事本未启动。"))
(vlax-invoke DWX 'SetWindowTextW jsb "虚拟按键演示中...")
;;SetWindowPos 激活记事本并获取焦点, 各参数如下
;; -1将窗口置于所有非顶层窗口之上
;; 300 左边界距离,200 顶边界距离
;; 500 指定窗口宽度像素,400 高度像素
;; 64立即显示窗口
(vlax-invoke DWX 'SetWindowPos jsb -1 300 200 500 400 64)
(if (zerop (vlax-invoke DWX 'GetKeyState 20))(progn
(vlax-invoke DWX 'keybd_event 20 0 0 0) ;;CAPS LOCK 键按下
(vlax-invoke DWX 'keybd_event 20 0 2 0) ;;CAPS LOCK 键弹起
))
(foreach x (vl-string->list "HOW ARE YOU FINE THANKS")
(vlax-invoke DWX 'keybd_event x 0 0 0) ;;模拟键按下
(vlax-invoke DWX 'keybd_event x 0 2 0) ;;模拟键弹起
(vlax-invoke DWX 'Sleep 300) ;;系统等待 0.3 秒
(vlax-invoke DWX 'Beep 800 30) ;;发出按键声
)
(vlax-invoke DWX 'SetWindowTextW jsb "演示完毕!")
(princ)
)
;;返回某程序最近打开的一个兄弟程序句柄,参数为标题
;; GetWindow5 第一个子窗口0 第一个兄弟窗口2 下一个窗口
(defun get-fun-hand(h s / x)
(vlax-invoke DWX 'Register "user32" "GetWindow" "i=mm" "r=m")
(setq x (vlax-invoke DWX 'GetWindow h 0))
(while (and (/= x 0)(null (wcmatch (get-fun-txt x) s)))
(setq x (vlax-invoke DWX 'GetWindow x 2))
) x
)
;;获取某程序或控件的标题内容,参数为句柄
;;(get-fun-txt 1378520)
(defun get-fun-txt(h / ss pStr)
(vlax-invoke DWX 'Register "user32" "GetWindowTextW" "i=hpm" "r=m")
(setq ss (vlax-invoke DWX 'Space 256 " "))
(setq pStr (vlax-invoke DWX 'StrPtr ss))
(vlax-invoke DWX 'GetWindowTextW h pStr 256)
(vlax-invoke DWX 'strget pStr)
)
利用 DynamicWrapperX多少可以弥补一下 lisp 的弱点,例如:对指针的控制、多线程操作、执行高效的汇编代码等。
DynamicWrapperX下载链接详见 http://bbs.mjtd.com/thread-176996-1-1.html5楼
有兴趣的同学可以用 DWX 来引用 RAR 公司提供的 dll,这样可以用 lisp 调用 rar 函数进行压缩或解包,即使在系统里有没有安装 WinRAR 都无所谓了。 本帖最后由 yxp 于 2018-4-13 11:04 编辑
669423907 发表于 2018-4-13 10:22
可以用来开启数字键 numlock (只开不关),numlock总有时候会莫名其妙的关闭,目前用vbs只开不关
'打开数 ...
用什么脚本,用 lisp 也可以啊:
;;检测 NUM LOCK 状态,如果关闭就打开。
;;将本函数加入反应器,可以使 NUM LOCK 在 CAD 运行期间一直打开。
(defun c:OpenNumLock( / DWX)
(setq DWX (vlax-create-object "DynamicWrapperX"))
(vlax-invoke DWX 'Register "user32" "GetKeyState" "i=n" "r=l")
(vlax-invoke DWX 'Register "user32" "keybd_event" "i=llll" "r=m")
(if (= 0 (vlax-invoke DWX 'GetKeyState 144))(foreach x '(0 2)(vlax-invoke DWX 'keybd_event 144 0 x 0)))
(princ)
)
请教版主
批打印时每生成一个PDF以后
都会在PDF浏览器中打开
希望累计打印50张图纸以后
关闭PDF浏览器
避免内存占用过大
已用下面的语句获取了PDF浏览器的句柄
如何关闭就不知道怎么弄了
;;变量初始化
(setq *acad* (vlax-get-acad-object)
*doc* (vla-get-ActiveDocument *acad*)
hCAD (vla-get-hwnd *acad*) ;;顶层 CAD 对象句柄
hdwg (vla-get-hwnd *doc*) ;;当前 dwg 对象句柄
*dwx* (vlax-get-or-create-object "DynamicWrapperX");;创建一个 DWX 对象
)
;;Windows API 函数声明
(vlax-invoke *dwx* 'Register "shell32.dll" "ShellExecuteW" "i=hwwwwl" "r=m")
(vlax-invoke *dwx* 'Register "user32" "SetWindowTextW" "i=hw" "r=m")
(vlax-invoke *dwx* 'Register "user32" "GetKeyState" "i=n" "r=l")
(vlax-invoke *dwx* 'Register "user32" "keybd_event" "i=llll" "r=m")
(vlax-invoke *dwx* 'Register "user32" "SetWindowPos" "i=hmmmmmm" "r=m")
(vlax-invoke *dwx* 'Register "kernel32" "Beep" "i=mm" "r=m")
(vlax-invoke *dwx* 'Register "kernel32" "Sleep" "i=m")
(setq name "SD-51" pdf_num 51) ;;假定已打印50张
(setq jsb (get-fun-hand hCAD (strcat "*" name "*.pdf*"))) ;;获取PDF浏览器窗体的句柄
(if (> pdf_num 50)
(...);;如何关闭PDF浏览器???
)
完全不懂VB
看帮助似乎要用到“CloseHandle”
但是下面的语句没能达到预期的目的
(vlax-invoke *dwx* 'Register "kernel32" "CloseHandle" "i=h")
(vlax-invoke *dwx* 'CloseHandle jsb)
本帖最后由 yxp 于 2018-5-12 14:17 编辑
masterlong 发表于 2018-5-12 13:54
如何控制某个已打开窗体
已经摸到点边
首先通过窗体标题栏的文字内容
参考一下
SetWindowPos
;;参数 2:
;; 1 将窗口置于窗口列表底部
;; 0 将窗口置于Z序列的顶部;Z序列代表在分级结构中,窗口针对一个给定级别的窗口显示的顺序
;; -1 将窗口置于列表顶部,并位于任何最顶部窗口的前面(类似 QQ 界面)
;; -2 将窗口置于列表顶部,并位于任何最顶部窗口的后面(正常)
;;参数 34: 窗口坐标 x y
;;参数 56: 窗口大小 w h
;;参数 7:
; 1 保持当前大小
; 2 保持当前位置
; 4 保持窗口在列表的当前位置
; 8 窗口不自动重画
; 16 不激活窗口
; 32 围绕窗口画一个框
; 64 显示窗口
好贴,我来沙发 可以用来开启数字键 numlock (只开不关),numlock总有时候会莫名其妙的关闭,目前用vbs只开不关
'打开数字键盘 yu2n 2017-4-11 http://www.bathome.net/thread-43783-1-1.html
Set objWord = CreateObject("Word.Application")
If objWord.NumLock = False Then '<>
Set WshShell = CreateObject("WScript.shell")
WshShell.SendKeys "{NUMLOCK}" '大小写{CapsLock}
End If
objWord.Quit
Set objWord = Nothing
Set WshShell = Nothing 有时会失灵,运行好多次都开不了 问一个问题
这种方式在win7、10里
可以控制已经打开的文件夹吗?
是挺不错的,就是太麻烦了,当然对于只用lisp的朋友 ,那是非常好的 是lsp失灵,有时也会数字指示灯闪一下 文章很好,但是对于WindowsAPI不熟悉的同学去调用API还是很困难的,调用API确实弥补了lisp的不足!啥时候楼主给个多线程的例子吧!或者是非模态对话框的例子,不知道能搞的了不? 这个用不用提前设置引用什么库呢