几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量  


返回   几何尺寸与公差论坛------致力于产品几何量公差标准GD&T (GDT:ASME)|New GPS(ISO)研究/CAD设计/CAM加工/CMM测量 » 仿射空间:CAX软件开发(三)二次开发与程序设计 » CAD二次开发 » AutoCAD二次开发 » ObjectARX(AutoLISP)
用户名
密码
注册 帮助 会员 日历 银行 搜索 今日新帖 标记论坛为已读


回复
 
主题工具 搜索本主题 显示模式
旧 2009-04-26, 03:18 PM   #1
yang686526
高级会员
 
注册日期: 06-11
帖子: 14579
精华: 1
现金: 224494 标准币
资产: 234494 标准币
yang686526 向着好的方向发展
默认 [讨论]lisp调用dll动态win32api的实现

[讨论]lisp调用dll动态win32api的实现
www.dimcax.com
[讨论]lisp调用dll动态win32api的实现
aroom
发帖:
各位高手来共同来讨论讨论,它是如何实现的呢?
在网上找了一段动态调用外部函数的vb代码。
option explicit
public declare function loadlibrary lib "kernel32" alias "loadlibrarya" (byval lplibfilename as string) as long
public declare function getprocaddress lib "kernel32" (byval hmodule as long, byval lpprocname as string) as long
public declare function callwindowproc lib "user32" alias "callwindowproca" (byval lpprevwndfunc as long, byval hwnd as long, byval msg as long, byval wparam as long, byval lparam as long) as long
public declare function freelibrary lib "kernel32" (byval hlibmodule as long) as long
public declare sub copymemory lib "kernel32" alias "rtlmovememory" (lpdest as any, lpsource as any, byval cbytes as long)
private m_opindex as long '写入位置
private m_opcode() as byte 'assembly 的opcode
public function rundll32(byval isunload as boolean, byval strlibfilename as string, strprocname as string, paramarray params()) as long
dim hproc as long
dim hmodule as long
redim m_opcode(400 + 6 * ubound(params)) '保留用来写m_opcode
'读取api库
hmodule = loadlibrary(byval strlibfilename)
if hmodule = 0 then
msgbox "函数库library:" + chr(13) + strlibfilename + chr(13) + "读取失败!"
rundll32 = 0
exit function
end if

'取得函数地址
hproc = getprocaddress(hmodule, byval strprocname)
'msgbox "参数2:" + strlibfilename + chr(13) + "参数3:" + strprocname
if hproc = 0 then
msgbox "提示:" + chr(13) + strprocname + chr(13) + "函数读取失败!", vbcritical
freelibrary hmodule
rundll32 = 0
exit function
end if
'执行assembly code部分
rundll32 = callwindowproc(getcodestart(hproc, params), 0, 1, 2, 3)
'一些函数需要驻留这就先不释放
if isunload then freelibrary hmodule '释放空间
end function
'public function rundll32(libfilename as string, procname as string, paramarray params()) as long
' dim hproc as long
' dim hmodule as long
'
' redim m_opcode(400 + 6 * ubound(params)) '保留用来写m_opcode
' '读取api库
' hmodule = loadlibrary(byval libfilename)
' if hmodule = 0 then
' msgbox "library读取失败!"
' exit function
' end if
'
' '取得函数地址
' hproc = getprocaddress(hmodule, byval procname)
' if hproc = 0 then
' msgbox "函数读取失败!", vbcritical
' freelibrary hmodule
' exit function
' end if
'
'
' '执行assembly code部分
' rundll32 = callwindowproc(getcodestart(hproc, params), 0, 1, 2, 3)
'
' freelibrary hmodule '释放空间
'end function
private function getcodestart(byval lngproc as long, byval arrparams as variant) as long
'---以下为assembly部分--
'作用:将函数的参数压入堆栈

dim lngindex as long, lngcodestart as long

'程序起始位址必须是16的倍数
'varptr函数是用来取得变量的地址
lngcodestart = (varptr(m_opcode(0)) or &hf) + 1

m_opindex = lngcodestart - varptr(m_opcode(0)) '程序开始的元素的位置

'前面部分以中断点添满
for lngindex = 0 to m_opindex - 1
m_opcode(lngindex) = &hcc 'int 3
next lngindex

'--------以下开始放入所需的程序----------

'将参数push到堆栈
'由于是stdcall call 参数由最后一个开始放到堆栈
for lngindex = ubound(arrparams) to 0 step -1
addbytetocode &h68 'push的机器码为h68
addlongtocode clng(arrparams(lngindex)) '参数地址
next lngindex

'call hproc
addbytetocode &he8 'call的机器码为he8
addlongtocode lngproc - varptr(m_opcode(m_opindex)) - 4 '函数地址 用call的定址

'-----------结束所需的程序--------------

'返回呼叫函數
addbytetocode &hc2 'ret 10h
addbytetocode &h10
addbytetocode &h0

getcodestart = lngcodestart
end function
private sub addlongtocode(ldata as long)
'将long类型的参数写到m_opcode中
copymemory m_opcode(m_opindex), ldata, 4
m_opindex = m_opindex + 4
end sub
private sub addinttocode(idata as byte)
'将integer类型的参数写道m_opcode中
copymemory m_opcode(m_opindex), idata, 2
m_opindex = m_opindex + 2
end sub
private sub addbytetocode(bdata as byte)
'将byte类型的参数写道m_opcode中
m_opcode(m_opindex) = bdata
m_opindex = m_opindex + 1
end sub
在vb中新建dll工程命令如:nbtlibs,然后新建一个模块命令如:callapibyname,将上面代码输入。然后再新建一类模块命令如:win32api,并输入:
public function test1(hwnd as long, byval s1 as string, byval s2 as string) as long
s1 = strconv(s1, vbfromunicode)
s2 = strconv(s2, vbfromunicode)
test1 = rundll32(true, "user32", "messageboxa", hwnd, strptr(s1), strptr(s2), 0&)
end function
在vb中最后生成dll文件,将其复制到你需要的目录,如d:\
然后在windows的命令运行窗口(ctrl+r)中运行:regsvr32 d:\nbtlibs.dll,这样dll就在windows中注册成功了。
然后在cad的vlisp中
( test1 ( obj ret hwnd errormsg)
( hwnd 153)
( obj ( "nbtlibs.win32api"))
( errormsg ( 'vlax-invoke-method
( obj "test1" 0 "内容 " "标题")
) ;_ 结束vl-catch-all-apply
) ;_ 结束setq
( obj)
( ( errormsg)
( ( "发生下列错误: "
( errormsg)
) ;_ 结束strcat
)
) ;_ 结束if
errormsg
) ;_ 结束defun
然后运行(test1),就能实现对话框了。
d
但是在lisp中动态调用方面却总是因为参数类型问题无法调用成功
在vb中win32api类模块中输入:
public function win32api(byval libfilename as string, byval procname as string, paramarray params1()) as long
'public function win32api(byval libfilename as string, byval procname as string, byval params1 as variant) as long
'处理字符串变量
dim lngindex as long
for lngindex = 0 to ubound(params1)
if vartype(params1(lngindex)) = vbstring then
params1(lngindex) = strptr(strconv(params1(lngindex), vbfromunicode))
end if
next lngindex
win32api = rundll32(true, libfilename, procname, params1)
'("user32", "messageboxa", hwnd, varptr(s1(0)), varptr(s2(0)), 0&)
end function
然后在lisp中
( test1 ( obj ret hwnd errormsg)
( hwnd 153)
( obj ( "nbtlibs.win32api"))
( errormsg ( 'vlax-invoke-method
( obj "win32api" "user32" "messageboxa" 0 "测试内容" "标题" 0)
) ;_ 结束vl-catch-all-apply
) ;_ 结束setq
( obj)
( ( errormsg)
( ( "发生下列错误: "
( errormsg)
) ;_ 结束strcat
)
) ;_ 结束if
errormsg
) ;_ 结束defun
调用却不成功!
出错信息:发生下列错误: automation 错误。 类型不匹配
d
得解决参数传递问题呀!
各位快来讨论讨论!!
d
我曾做过试验,但基于单变量,多变量时可用variant解决,当时的实验总结如下,或许对你有帮助。
1、在vb中,选择创建activex dll,在右上方将修改工程名为testdll,修改类名为test1
在代码区输入下列代码:
public function vvvaa(byval a as double) as double
vvvaa = a
end function
用文件菜单编译成testdll.dll
于是创建了一个testdll.dll文件,其中包含一个test1类,test1类中有含public function vvvaa定义。
2、在autolisp中,用
(setq vvvv (vlax-create-object "testdll.test1"))
(vlax-invoke-method vvvv "vvvaa" 3)
可获得返回值3(与输入值一致)
或用
(defun vvvv ( a / vbcls out)
(setq vbcls
(vlax-invoke-method
(vlax-get-acad-object)
"getinterfaceobject"
"testdll.test1"
)
)
(setq out
(vlax-invoke-method vbcls "vvvaa" a)
)
(vlax-release-object vbcls)
out
)
(vvvv 30)
;;可得到返回值30(与输入值一致)
;;注意事项:
;;一、函数定义时的问题
;; 1) 函数定义时应采用public。
;; 2) 输入参数时必须采用byval,否则输入参数传不进dll。
;; 3) 如果输入参数是一个表,可将参数定义为variant类型。
;; 4) 如果返回参数是一个表,可将函数定义为variant类型,返回值用array构造。
;;二、autolisp中对返回参数的处理
;;1)函数定义返回简单参数时,可直接得到结果
;;2)函数定义返回variant,且结果为简单参数时,用vlax-variant-value得到结果
;;3)函数定义返回variant,且结果为表时,
;; 用(mapcar 'vlax-variant-value (vlax-safearray->list (vlax-variant-value得到表结果
;;三、autolisp中对输入参数的处理
;;1)函数定义输入为简单参数时,可直接填入数据
;;2)函数定义输入为variant时,如输入简单参数,可直接填入数据也可用vlax-make-variant输入
;;3)函数定义输入为variant时,如输入表时,用如下示例方法:
;; (setq aa0 (vlax-make-safearray vlax-vbvariant '(0 . 2)))
;; (vlax-safearray-fill aa0 '(9 2 "3"))
;; (setq aa1 (vlax-make-variant aa0 ))
d
非常感谢分享经验.这可是书本上学不到的东西~~~~~
d
收下先,说不定会用到
yang686526离线中   回复时引用此帖
GDT自动化论坛(仅游客可见)
回复


主题工具 搜索本主题
搜索本主题:

高级搜索
显示模式

发帖规则
不可以发表新主题
不可以回复主题
不可以上传附件
不可以编辑您的帖子

vB 代码开启
[IMG]代码开启
HTML代码关闭



所有的时间均为北京时间。 现在的时间是 06:13 PM.


于2004年创办,几何尺寸与公差论坛"致力于产品几何量公差标准GD&T | GPS研究/CAD设计/CAM加工/CMM测量"。免责声明:论坛严禁发布色情反动言论及有关违反国家法律法规内容!情节严重者提供其IP,并配合相关部门进行严厉查处,若內容有涉及侵权,请立即联系我们QQ:44671734。注:此论坛须管理员验证方可发帖。
沪ICP备06057009号-2
更多