日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

vs2019 Com組件初探-實(shí)現(xiàn)vbs的CreateObject函數(shù)邏輯

 頭號(hào)碼甲 2021-06-27

vs2019 Com組件初探-簡(jiǎn)單的COM編寫以及實(shí)現(xiàn)跨語(yǔ)言調(diào)用

上一篇實(shí)現(xiàn)了如何編寫基于IDispatch接口的COM以及vbs如何調(diào)用編寫的COM

本次主要是實(shí)現(xiàn)VBS的CreateObject函數(shù)的邏輯,也就是在不知道類名的情況下如何調(diào)用基于IDispathc接口的COM

前提條件

  1、掌握C++基礎(chǔ)語(yǔ)法

  2、平臺(tái)安裝 vs2019

  3、本地平臺(tái)為 windows 10 1909 X64

  4、基本的DLL編程知識(shí) (不是必備)

本次目標(biāo)

  1、創(chuàng)建DLL并實(shí)現(xiàn)CreateObject函數(shù)

  2、寫一個(gè)調(diào)用DLL的demo

1、創(chuàng)建DLL并實(shí)現(xiàn)CreateObject函數(shù)

  首先通過(guò)VS創(chuàng)建一個(gè) 動(dòng)態(tài)鏈接庫(kù)

  

  在編寫之前先梳理程序的執(zhí)行流程

    初始化 Com庫(kù)

    獲取函數(shù)指針

    傳入?yún)?shù) 

    調(diào)用函數(shù)指針

    卸載Com庫(kù)

  接下來(lái)就開(kāi)始寫我們的DLL

    vs2019 創(chuàng)建DLL項(xiàng)目后系統(tǒng)會(huì)默認(rèn)多出來(lái)頭文件

      

    以及源文件

      

  我們打開(kāi)pch.h頭文件定義我們的函數(shù)聲明

    

    參數(shù)為 COM組件progID,函數(shù)名,參數(shù)數(shù)量,變長(zhǎng)參數(shù)

    extern "C" 以C的方式定義

    _declspec(dllimport) 定義此函數(shù)為要導(dǎo)出的函數(shù)

  新建一個(gè)ComInit.h 定義Com庫(kù)的初始化和卸載庫(kù)函數(shù)

 1 // ComInit.h 2  3 #pragma once 4 static bool _init = false; 5  6 // 初始化 7 bool Init(); 8  9 // 結(jié)束初始化10 void Release();

  新建一個(gè)ComInit.cpp 實(shí)現(xiàn)Init和Release函數(shù)

// ComInit.cpp#include "pch.h"#include "ComInit.h"bool Init()
{if (_init == true)
    {return _init;
    }else{if (S_OK == CoInitialize(NULL))
            _init = true;else_init = false;return _init;
    }return false;
}void Release()
{if (true == _init)
    {
        CoUninitialize();
        _init = false;
    }
}

  之后打開(kāi)pch.cpp實(shí)現(xiàn)CreateObject函數(shù)

 1 #include "pch.h" 2 #include "ComStart.h" 3 #include <assert.h> 4 #include <atlbase.h> 5  6 // 報(bào)錯(cuò)宏 7 #define ASSERT(s) if((s) == true) 8  9 // Com類名,函數(shù)名,傳入的參數(shù)數(shù)量,變長(zhǎng)參數(shù)10 VARIANT CreateObject(const WCHAR* __comname,const WCHAR* __funcname,int __count, ...)11 {12     /* Com注冊(cè)到系統(tǒng)后使用 */13    14     // 是否成功初始化15     if (true == Init())16     {17         // ProgId值存放18         CLSID clsid;19 20         // 通過(guò) ProgID 取得組件的 CLSID21         // CLSID 值存放在注冊(cè)表 HKEY_CLASSES_ROOT [以__comname加.1為鍵值(MyCom.FirstClass.1)]22         HRESULT hr = ::CLSIDFromProgID(__comname, &clsid);23 24         ASSERT(S_OK != hr)25             assert(hr != S_OK);26 27         // 智能指針獲取 IUnknow28         CComPtr<IUnknown>spUnk;29 30         /* 31         *   CoCreateInstance32         *       CLSIDFromProgId獲取的值33         *       指向接口IUnknown的指針34         *       運(yùn)行可執(zhí)行代碼的上下文[CLSCTX_ALL 為所有]35         *       IID_IUnknown為返回類型36         *       用來(lái)接收指向Com對(duì)象接口地址的指針變量37         */38         // 獲取IUnknow內(nèi)容 39         hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IUnknown, (LPVOID*)&spUnk);40 41         ASSERT(S_OK != hr)42             assert(hr != S_OK);43         44         // 通過(guò)IUnknown智能指針,聲明新的IDispatch智能指針45         CComDispatchDriver spDisp(spUnk);46 47         // 參數(shù)數(shù)組48         VARIANT* __args = new VARIANT[__count];49 50         // 變長(zhǎng)參數(shù)變量51         va_list ap;52 53         // 定位到第一個(gè)函數(shù)變長(zhǎng)參數(shù)54         va_start(ap, __count);55 56         // 循環(huán)獲取變長(zhǎng)參數(shù),并轉(zhuǎn)換為 VARIANT 類型放入 __args變量57         for (auto i = 0; i < __count; i++)58             __args[i] = va_arg(ap, VARIANT);59 60         // 結(jié)束變長(zhǎng)參數(shù)61         va_end(ap);62 63         // Com函數(shù)返回值存放64         VARIANT __ret;65 66         // 執(zhí)行Com函數(shù)67 68         /*69         *   [InvokeN]70         *       函數(shù)名71         *       函數(shù)參數(shù)72         *       函數(shù)數(shù)量73         *       返回值存放處74         */75         hr = spDisp.InvokeN((LPCOLESTR)__funcname, __args, __count, &__ret);76        77         ASSERT(S_OK != hr)78             assert(hr != S_OK);79 80         // 內(nèi)存回收81         delete[] __args;82 83         // 卸載 Com庫(kù)84         Release();85 86         // 返回值87         return __ret;88     }89 90     assert(_init == false);91 }

  完成后編譯(CTRL+B)獲取到新的dll和lib文件(x64)以及項(xiàng)目的pch.h頭文件

    

    

2、寫一個(gè)調(diào)用DLL的demo

  vs2019 新建基于 控制臺(tái)程序 的項(xiàng)目

  

  移動(dòng)dll和lib以及pch.h文件到新建項(xiàng)目目錄下,并對(duì)pch.h文件添加代碼

// pch.h#pragma once#include <combaseapi.h>// 新添加的代碼#pragma comment(lib,"ComPack.lib")extern "C" _declspec(dllimport) VARIANT CreateObject(const WCHAR * __comname, const WCHAR * __funcname, int __count, ...);

   找到main函數(shù) 寫入調(diào)用代碼

#include <iostream>#include "pch.h"int main()
{// 參數(shù)類型必須為VARIANT    VARIANT __param1;// 參數(shù)類型為 LONG__param1.vt = VT_I4;// 參數(shù)值為 2__param1.lVal = 2;// 獲取ComTest.Temp并調(diào)用Number 函數(shù) 參數(shù)數(shù)量為1 對(duì)Number函數(shù)傳入?yún)?shù)__param1VARIANT __ret = CreateObject(L"ComTest.Temp", L"Number",1, __param1);

    std::cout << __ret.lVal << std::endl;
}

  執(zhí)行并運(yùn)行顯示執(zhí)行結(jié)果

  

  運(yùn)行出現(xiàn)錯(cuò)誤,檢查調(diào)用的Com是否已經(jīng)注冊(cè)

  如何注冊(cè)我在上一篇里面有講過(guò)

  接下來(lái)修改代碼嘗試調(diào)用Wscript.shell里面的Run函數(shù)

#include <iostream>#include "pch.h"int main()
{
    VARIANT __param1;// 參數(shù)類型為BSTR__param1.vt = VT_BSTR;// 創(chuàng)建BSTR格式的字符串__param1.bstrVal = SysAllocString(L"notepad.exe");// 調(diào)用函數(shù)并釋放BSTRVARIANT __ret = CreateObject(L"Wscript.shell", L"run",1, __param1);
    SysFreeString(__param1.bstrVal);
}

  值得一提的是 COM組件的字符串和以往的字符串有所不同,創(chuàng)建方式和銷毀方式也不同

  SysAllocString為創(chuàng)建BSTR字符串

  SysFreeString 為釋放BSTR字符串

  運(yùn)行結(jié)果可以看到已經(jīng)成功的執(zhí)行了系統(tǒng)命令,打開(kāi)了一個(gè)記事本

  

注意事項(xiàng):

  com基于IDispatch 接口才可以調(diào)用

  Com必須已經(jīng)注冊(cè)到系統(tǒng) (小心誤刪或者移動(dòng)路徑)

  卸載DLL函數(shù)為  regsvr32.exe -ui [DLL未知]

  DLL對(duì)應(yīng)版本盡量一致

github源碼:

  3065190005/ComTest: ComTest Code (github.com)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多