百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

用 aardio 我们可以简单地调用 C++ 代码

liebian365 2024-10-24 14:36 27 浏览 0 评论

我们今天就不说下面这种 aardio 调用原生 API 如何简单:

var point = { INT x; INT y; }
::User32.GetCursorPos(point);

我们今天要玩一点难度高一些的,例如玩 C++ 地看到头都打转的 COM 接口,我们今天说的 COM 接口,也不说那种写起来累人用起来很舒服的 COM 控件。

我们今天要说几个难度高一些的:
1、直接调用 VC++ 实现了 IDispatch 接口指针。
2、直接用 C++ 专有的 thiscall 约定调用 C++ 对象。

一般调用 COM 控件,我们知道要先注册 COM 控件,但是一般注册 COM 控件还是比较麻烦,大多数需要管理权限注册,出现恼人的警告对话框,体验不是很好。在 aardio 中一般可以免管理权限注册,甚至可以免注册调用很多 COM 控件。

但是仍然有一些 COM 控件比较顽固是不能免注册调用的,其实 COM 控件注册啊什么的搞得很复杂,最终只是为了创建一个 IDispatch 对象,如果我们可以跳过上面这些所有的步骤,这会是非常舒服的。

我们用 VC++ 创建 IDispatch 对象,然后直接拿到原生的 IDispatch 接口指针,并且直接转换为 aardio 对象,这带来的好处是:

1、不用再注册 COM 控件了。
2、当然也不用什么免注册了。
3、可以直接通过内存加载 DLL,不用再带一个 DLL 文件了。

今天我们用 VC6 来写一个简单的 DLL 做一下演示,别小看 VC6,VC6 是唯一所有操作系统都自带的系统 C++ 运行时,所以可以生成极小的 DLL,而且一般是够用的,当然你要换新版 VC++ ,写法一样。

先看 aardio 调用代码有多简洁:

import console;

//加载 DLL
var dll = raw.loadDll(#34;/test.disp.dll",,"cdecl");

//创建 COM 对象,aardio 可自动支持 IDispatch 接口
import com;
var comObject = com.QueryObjectR( dll.CreateIDispatchObjectP() );
 
//使用 COM 对象
comObject.name = "测试";
console.log( comObject.name ); 
console.pause();

是不是简洁到难以置信?!
要做到上面的效果,一个编程语言需要同时做到能支持原生 API 开发,还要能支持 COM 动态接口对象,能做到这 2 样的编程语言其实非常少。而真正做到简洁方便好用的就更少了。

下面我们再看一下上面这个 test.disp.dll 的 C++ 源代码,这个先要有心理准备,世界上最复杂的编程语言不是白叫的,如果学 aardio 这样简单的编程语言让我叫苦不迭,我很难保证你看到下面的 C++ 代码不会晕过去。

不过我已经尽力把下面的代码处理到尽可能简单了,你不需要安装巨无霸的 VC++ 开发环境,直接运行下面的代码就可以编译生成 DLL,aardio 自带 VC6 扩展库。

import vc6;
import console; 
var vc = vc6( "/",, console.open() )  

//输入 C++ 源码
vc.cpp  = /****** 
    #include <afxwin.h> 
    #include <afxdisp.h>
   
    class CTestObject: public CCmdTarget
    { 
        DECLARE_DYNCREATE(CTestObject)
        CTestObject(); 
    protected:
        virtual ~CTestObject();
        CString strName;
    public:
        afx_msg BSTR GetName();
        afx_msg void SetName(LPCTSTR lpszName); 
        DECLARE_DISPATCH_MAP()
    };
    
    IMPLEMENT_DYNCREATE(CTestObject, CCmdTarget)
    CTestObject::CTestObject() {
        EnableAutomation();
        AfxOleLockApp(); 
    }
    CTestObject::~CTestObject() {
        AfxOleUnlockApp();
    }
    
    BEGIN_DISPATCH_MAP(CTestObject, CCmdTarget) 
        DISP_PROPERTY_EX(CTestObject, "version", GetName, SetName, VT_BSTR) 
    END_DISPATCH_MAP()
     
    BSTR CTestObject::GetName() 
    { 
         return strName.AllocSysString();
    }
    
    void  CTestObject::SetName(LPCTSTR lpszName) 
    { 
        strName = lpszName;
    } 
    
    extern "C" __declspec(dllexport) LPDISPATCH __cdecl CreateIDispatchObject() {
       LPDISPATCH pDispatch = ( new CTestObject() )->GetIDispatch(FALSE);//参数FALSE指定不要添加引用计数
       return pDispatch;
    }
******/ 

//编译生成DLL 
vc.exec(
    'cl *.cpp'
    ,'/W3' /*警告等级*/
    ,'/MD' /*使用多线程动态运行库*/
    ,'/O2 /Ot /EHsc' /*代码优化选项*/
    ,'/D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_AFXDLL" ' /*定义常数和宏*/
    ,'/I"./INCLUDE"'/*指定头文件目录*/
    ,'kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib' /*导入库*/
    ,'/link /SUBSYSTEM:WINDOWS /MACHINE:X86' /*后面是链接参数 */
    ,'/out:test.disp.dll'/*输出文件名*/
    ,'/dll' /*输出DLL*/ 
    ,'/LIBPATH:".\LIB" /LIBPATH:".\LIB2"' /*指定库目录*/
)

好吧,我们进入下一个目标,使用 thiscall 协议调用 C++ 对象,现在你见过 C++ 代码了,我就不再把 C++ 代码,aardio 代码分开发了,用 C++ 编译 DLL,再用 aardio 调用 C++ 对象,一锅炖:

import vc6;
import console; 
console.open();

var vc = vc6( "/" )  

//输入C++源码
vc.cpp = /****** 
    #include <windows.h> 
      
    struct TestInfo{
        int x;
        int y;
        BYTE name[256];
    };
    
    class CTestObject
    {
    public: 
        //注意函数声明前加上 virtual 以支持 aardio 中的 raw.interface
        virtual  void getName(char *buffer,int len); 
        virtual  void getInfo(TestInfo *pInfo);
    };
    
    void CTestObject::getName(char *buffer,int len){
        strcpy(buffer,"测试");
    }
    
    void CTestObject::getInfo(TestInfo *pInfo){
        pInfo->x = 1;
        pInfo->y = 2;
        strcpy((char *)pInfo->name,"测试");
    }
    
    extern "C" __declspec(dllexport) CTestObject* __cdecl CreateTestObject() { 
        return new CTestObject();
    }
    
    extern "C" __declspec(dllexport) void __cdecl DeleteTestObject( CTestObject* pTest) {
        delete pTest;
    }
******/

//编译生成DLL 
vc.exec(
    'cl *.cpp'
    ,'/W3' /*警告等级*/
    ,'/MD' /*使用多线程动态运行库*/
    ,'/O2 /Ot /EHsc' /*代码优化选项*/
    ,'/D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL"' /*定义常数和宏*/
    ,'/I"./INCLUDE"'/*指定头文件目录*/
    ,'kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib' /*导入库*/
    ,'/link /SUBSYSTEM:WINDOWS /MACHINE:X86' /*后面是链接参数 */
    ,'/out:test.dll'/*输出文件名*/
    ,'/dll' /*输出DLL*/ 
    ,'/LIBPATH:".\LIB" /LIBPATH:".\LIB2"' /*指定库目录*/
)

var dll = raw.loadDll("/test.dll",,"cdecl");

import raw.interface;
class testObject{
  ctor(){
    //创建 C++ 对象,并获取指针,注意这里使用了 P 尾标获取指针。
    var pTest = dll.CreateTestObjectP();
    
    //C++ 对象指针转换为 aardio 对象。
    this = ..raw.interface( pTest,"
        void getName(string &buffer,int len);
        void getInfo(struct &pInfo); 
        ","thiscall" //注意调用约定为thiscall
    )
    
    //添加析构函数  
    ..table.gc(this,"delete")  
  };
  delete= function(){
    if(!owner.deleted){
      dll.DeleteTestObject( owner );
      owner.deleted = true;
    } 
  };
}

//创建对象
var obj = testObject();

//调用 C++ 函数
var name = obj.getName(25,25);
console.log(name);

//调用 C++ 函数
var info = obj.getInfo({ int x;int y;BYTE name[256]})
console.log( info.name  );

console.pause();

好吧,如果你只是想试着跑几句 C++ 代码,并不想生成 DLL,就像硬盘干干净净的,还能跑一下 VC++ 代码,aardio 提供了一个 vc6.loadcode() 函数可以直接运行 VC++ 代码,示例如下:


import vc6;
import console; 

console.showLoading(" 正在加载 C++ 代码");
var dll = vc6.loadcode(`
#include <windows.h>  
#include <winioctl.h>  

extern "C" {
  __declspec( dllexport ) int __cdecl getValue() { 
    return CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS);
  }
}`);

var value = dll.getValue();
var str = string.format("0x%X",value);
console.log("已复制: " + str,value);

import win.clip;
win.clip.write(str);

console.pause();

相关推荐

记录一个ComboBox的设置问题,你可能没遇到过

ComboBox这个控件使用频率太高了,我从VC6编程开始就用它,一直用到C#到现在的Net6,要说我这么一个编程老手还能在它身上栽跟头,我都不敢相信。但是今天竟然被它无情的戏耍了。记录下这个问题,看...

组合框(Combo Box)应用之一_combo简单组合框

【分享成果,随喜正能量】对别人期待太高,本质上是对自身无能的逃避和推托,与其期待别人,不如依靠自己。你不害怕孤独,就不再寄期望于他人陪伴;你有底气解决问题,就不在寄期望于他人向你伸出援手。一个人期待值...

Qt之QComboBox定制(二)_qt on_combobox_activated

上一篇文章Qt之QComboBox定制讲到了qt实现自定义的下拉框,该篇文章主要实现了列表式的下拉框,这一节我还将继续讲解QComboBox的定制,而这一节我将会讲述更高级的用法,不仅仅是下拉列表框,...

从零开始系列,用C#做软件产品:私人日记(九)ComboBox入门

第八节的内容早已写好发布,结果一直在审核中,不知道触动了哪条神经。评论中看到有一些网友都在问为什么不用WPF来开发,在这里我统一说明下:1)WPF界面设计相对复杂。由于它是矢量的,需要额外有很多容器做...

QT-QSharedMemory_qt450-10是什么材料

1.QSharedMemory介绍...

进入Python的世界19-pyqt6不只是UI设计,其他模块功能如何运用

今天是大年初四,继续探讨pyqt6,给出使用的建议。PyQt6绝不仅仅局限于UI设计...

从零开始学Qt - 10:一文读懂Qt的元对象系统

Qt本身并不是一种编程语言,它实质上是一个跨平台的C++开发类库。它是用标准C++编写的,为开发GUI应用程序和非GUI应用程序提供了各种类。Qt对标准C++进行了扩展,引入一些新的概念和功能,例如信...

QT实现抖动文字和滚动文字,附源码

前言不知道大家有没有发现今天的文章有什么不一样,哈哈,我自己胡拼乱凑弄了一个logo,好不好看就先不说了,最起码萌萌哒...当然这不是今天的重点,在做logo的时候,我原本想让文字动起来的,奈何技术有...

Qt Concurrent的使用_qt是什么意思

1.简介QtConcurrent命名空间提供了高级api,使得无需使用诸如互斥、读写锁、等待条件或信号量等低级线程原语就可以编写多线程程序。使用QtConcurrent编写的程序会根据可用的...

Qt使用FFmpeg播放视频_qt使用ffmpeg播放视频功能

一、使用场景...

Qt中使用匿名函数lambda表达式_匿名函数lambda

一、为什么要使用匿名函数lamdba首先,lambda表达式可以使代码变得简单,C++中,一个lambda表达式表示一个可调用的代码单元。如代码:...

EtherCAT运动控制卡开发教程之Qt(中):小线段连续轨迹加工

今天,正运动小助手给大家分享一下EtherCAT运动控制卡开发教程之Qt,主要介绍一下如何通过Qt编程实现小线段轨迹连续加工,暂停与继续。...

送亲人,用1小时制作精美电子相框 | Qt 示例

今天给大家分享:...

Python之面向对象:综合应用,基于GUI实现会动的游戏英雄

引言本打算以上一篇文章作为面向对象模块的收尾,但是,犹豫了许久,还是决定再补充一篇,也就是今天这篇文章,打算基于Python的PyQt6/PySide6框架开发一个GUI程序,模拟实现一个在电脑桌面活...

Qt——常用数据类型_qt基本数据类型

1.基础类型因为Qt是一个C++框架,因此C++中所有的语法和数据类型在Qt中都是被支持的,但是Qt中也定义了一些属于自己的数据类型,下边给大家介绍一下这些基础的数类型。...

取消回复欢迎 发表评论: