ユーザ用ツール

サイト用ツール


youtube:vba-dll-005

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
youtube:vba-dll-005 [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1youtube:vba-dll-005 [2024/07/12 02:46] (現在) freemikan
行 1: 行 1:
 +====== Toymath3 ======
 +
 +作成日: 2023-09-02 (土)
 +
 +[[https://youtu.be/ZVBSrgK-9Lg|第5回 VBAでCOMを使う]]
 +
 +そのうち説明を追記予定。
 +===== test_Toymath3.xls =====
 +
 +==== Sheet1 (Sheet1) ====
 +
 +<file vba>
 +Sub test_Toymath3()
 +    'late-binding
 +    'Dim Calc As ToymathLib3.Calculator
 +    'Set Calc = CreateObject("Toymath3.Calculator.1")
 +
 +    'early-binding
 +    Dim Calc As New ToymathLib3.Calculator
 +
 +    X = Calc.Add(100, 200)
 +    Debug.Print X
 +
 +    Debug.Assert Calc.Add(10, 20) = 30
 +    Debug.Assert Calc.Sub(10, 20) = -10
 +    Debug.Assert Calc.Mul(10, 20) = 200
 +    Debug.Assert Calc.Div(10, 20) = 0
 +End Sub
 +</file>
 +
 +===== Toymath3 =====
 +
 +==== Makefile =====
 +
 +<file makefile>
 +MODNAME = toymath3
 +DLLFILE = ${MODNAME}.dll
 +IDLSRC = ${MODNAME}.idl
 +DEFFILE = ${MODNAME}.def
 +TLBFILE = ${MODNAME}.tlb
 +IDLOUT = ${MODNAME}.h ${MODNAME}_i.c ${MODNAME}_p.c ${TLBFILE} dlldata.c
 +RCSRC = ${MODNAME}.rc
 +RCBIN = ${MODNAME}.res
 +OUTDIR = output
 +SRCS = \
 + calculator.cpp \
 + calculatorclass.cpp \
 + modulelock.cpp \
 + exports.cpp
 +OBJS = ${SRCS:%.cpp=${OUTDIR}/%.o}
 +DEPS = ${SRCS:%.cpp=${OUTDIR}/%.d}
 +CPPFLAGS =
 +CXXFLAGS = -Wall -std=c++20 -fPIC
 +LDFLAGS =
 +LDLIBS = -lole32 -loleaut32 -luuid
 +
 +.PHONY: all
 +all: ${OUTDIR} ${IDLOUT} ${OUTDIR}/${DLLFILE}
 +
 +${OUTDIR}/${DLLFILE}: ${OBJS} ${OUTDIR}/${RCBIN} ${OUTDIR}/${MODNAME}_i.o
 + ${CXX} -shared -o $@ $^ ${DEFFILE} ${LDFLAGS} ${LDLIBS}
 +
 +${OUTDIR}/%.o: %.cpp
 + ${CXX} -c ${CXXFLAGS} -o $@ $< -MMD -MP ${CPPFLAGS}
 +
 +-include ${DEPS}
 +
 +${IDLOUT}: ${IDLSRC}
 + midl $<
 +    
 +${OUTDIR}/${RCBIN}: ${RCSRC} ${TLBFILE}
 + windres $< -O COFF -o $@
 +
 +${OUTDIR}/${MODNAME}_i.o: ${MODNAME}_i.c
 + gcc -c -o $@ $<
 +
 +${OUTDIR}:
 + mkdir -p ${OUTDIR}
 +
 +.PHONY: clean
 +clean:
 + ${RM} ${IDLOUT}
 + ${RM} -R ${OUTDIR}
 +
 +.PHONY: install
 +install: all
 + cp -f ${OUTDIR}\${DLLFILE} C:\code\lib
 +</file>
 +
 +==== calculator.h =====
 +
 +<file cpp>
 +#ifndef CALCULATOR_H
 +#define CALCULATOR_H
 +
 +#include "toymath3.h"
 +
 +class Calculator : public ICalculator {
 +public:
 +    Calculator(void);
 +
 +protected:
 +    virtual ~Calculator(void);
 +
 +public:
 +    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
 +    STDMETHODIMP_(ULONG) AddRef(void);
 +    STDMETHODIMP_(ULONG) Release(void);
 +    
 +    STDMETHODIMP Add(long x, long y, long *result);
 +    STDMETHODIMP Sub(long x, long y, long *result);
 +    STDMETHODIMP Mul(long x, long y, long *result);
 +    STDMETHODIMP Div(long x, long y, long *result);
 +    
 +private:
 +    LONG m_cRef;
 +};
 +
 +#endif // CALCULATOR_H
 +</file>
 +
 +==== calculator.cpp =====
 +
 +<file cpp>
 +#include "calculator.h"
 +
 +#include "modulelock.h"
 +#include <objbase.h>
 +
 +extern IID const IID_ICalculator;
 +
 +Calculator::Calculator(void) : m_cRef{0} {}
 +
 +Calculator::~Calculator(void) {}
 +
 +STDMETHODIMP Calculator::QueryInterface(REFIID riid, void **ppv) {
 +    if (riid == IID_IUnknown) {
 +        *ppv = static_cast<IUnknown *>(this);
 +    } else if (riid == IID_ICalculator) {
 +        *ppv = static_cast<ICalculator *>(this);
 +    } else {
 +        *ppv = nullptr;
 +        return E_NOINTERFACE;
 +    }
 +    
 +    reinterpret_cast<IUnknown *>(*ppv)->AddRef();
 +    return S_OK;
 +}
 +
 +STDMETHODIMP_(ULONG) Calculator::AddRef(void) {
 +    if (m_cRef == 0) {
 +        LockModule();
 +    }
 +    return InterlockedIncrement(&m_cRef);
 +}
 +
 +STDMETHODIMP_(ULONG) Calculator::Release(void) {
 +    LONG res = InterlockedDecrement(&m_cRef);
 +    if (res == 0) {
 +        delete this;
 +        UnlockModule();
 +    }
 +    return res;
 +}
 +
 +STDMETHODIMP Calculator::Add(long x, long y, long *result) {
 +    *result = x + y;
 +    return S_OK;
 +}
 +
 +STDMETHODIMP Calculator::Sub(long x, long y, long *result) {
 +    *result = x - y;
 +    return S_OK;
 +}
 +
 +STDMETHODIMP Calculator::Mul(long x, long y, long *result) {
 +    *result = x * y;
 +    return S_OK;
 +}
 +
 +STDMETHODIMP Calculator::Div(long x, long y, long *result) {
 +    *result = x / y;
 +    return S_OK;
 +}
 +</file>
 +
 +==== calculatorclass.h =====
 +
 +<file cpp>
 +#ifndef CALCULATORCLASS_H
 +#define CALCULATORCLASS_H
 +
 +#include <objbase.h>
 +
 +class CalculatorClassObject : public IClassFactory {
 +public:
 +    CalculatorClassObject(void);
 +    
 +protected:
 +    virtual ~CalculatorClassObject(void);
 +
 +public:
 +    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
 +    STDMETHODIMP_(ULONG) AddRef(void);
 +    STDMETHODIMP_(ULONG) Release(void);
 +    
 +    STDMETHODIMP CreateInstance(IUnknown *pUnknownOuter, IID const &iid, void **ppv);
 +    STDMETHODIMP LockServer(BOOL bLock);
 +
 +private:
 +    LONG m_cRef;
 +};
 +
 +#endif // CALCULATORCLASS_H
 +</file>
 +
 +==== calculatorclass.cpp =====
 +
 +<file cpp>
 +#include "calculatorclass.h"
 +
 +#include "calculator.h"
 +#include "modulelock.h"
 +
 +CalculatorClassObject::CalculatorClassObject(void) : m_cRef{0} {}
 +
 +CalculatorClassObject::~CalculatorClassObject(void) {}
 +
 +STDMETHODIMP CalculatorClassObject::QueryInterface(REFIID riid, void **ppv) {
 +    if (riid == IID_IUnknown) {
 +        *ppv = static_cast<IUnknown *>(this);
 +    } else if (riid == IID_IClassFactory) {
 +        *ppv = static_cast<IClassFactory *>(this);
 +    } else {
 +        *ppv = nullptr;
 +        return E_NOINTERFACE;
 +    }
 +    
 +    reinterpret_cast<IUnknown *>(*ppv)->AddRef();
 +    return S_OK;
 +}
 +
 +STDMETHODIMP_(ULONG) CalculatorClassObject::AddRef(void) {
 +    if (m_cRef == 0) {
 +        LockModule();
 +    }
 +    return InterlockedIncrement(&m_cRef);
 +}
 +
 +STDMETHODIMP_(ULONG) CalculatorClassObject::Release(void) {
 +    LONG res = InterlockedDecrement(&m_cRef);
 +    if (res == 0) {
 +        delete this;
 +        UnlockModule();
 +    }
 +    return res;
 +}
 +
 +STDMETHODIMP CalculatorClassObject::CreateInstance(IUnknown *pUnknownOuter, IID const &iid, void **ppv) {
 +    if (pUnknownOuter != nullptr) {
 +        return CLASS_E_NOAGGREGATION;
 +    }
 +    
 +    Calculator *pCalculator = nullptr;
 +    try {
 +        pCalculator = new Calculator;
 +    } catch (...) {
 +        return E_OUTOFMEMORY;
 +    }
 +    
 +    pCalculator->AddRef();
 +    HRESULT hr = pCalculator->QueryInterface(iid, ppv);
 +    pCalculator->Release();
 +    return hr;
 +}
 +
 +STDMETHODIMP CalculatorClassObject::LockServer(BOOL bLock) {
 +    //if (bLock) {
 +    //    LockModule();
 +    //} else {
 +    //    UnlockModule();
 +    //}
 +    return S_OK;
 +}
 +</file>
 +
 +==== modulelock.h =====
 +
 +<file cpp>
 +#ifndef MOUDLELOCK_H
 +#define MODULELOCK_H
 +
 +#include <objbase.h>
 +
 +void LockModule();
 +void UnlockModule();
 +LONG GetModuleLockCount();
 +
 +#endif // MODULELOCK_H
 +</file>
 +
 +==== modulelock.cpp =====
 +
 +<file cpp>
 +#include "modulelock.h"
 +
 +static LONG g_cLocks = 0;
 +
 +void LockModule() {
 +    InterlockedIncrement(&g_cLocks);
 +}
 +
 +void UnlockModule() {
 +    InterlockedDecrement(&g_cLocks);
 +}
 +
 +LONG GetModuleLockCount() {
 +    return g_cLocks;
 +}
 +</file>
 +
 +==== exports.cpp =====
 +
 +<file cpp>
 +#include "modulelock.h"
 +#include "calculatorclass.h"
 +// #include <olectl.h>
 +// #include <winreg.h>
 +// #include <string>
 +// #include <format>
 +
 +extern IID const LIBID_ToymathLib3;
 +extern CLSID const CLSID_Calculator;
 +
 +static WCHAR const *g_wszModulePath = L"C:\\code\\lib\\toymath3.dll";
 +static WCHAR const *g_wszProgId = L"Toymath3.Calculator.1";
 +
 +using RegKV = std::pair<std::wstring, std::wstring>;
 +
 +//static HRESULT RegisterServerWriteRegistry(RegKV const &kv) {
 +//    HKEY hkey;
 +//    if (long err = RegCreateKeyW(HKEY_CLASSES_ROOT, kv.first.c_str(), &hkey); err == ERROR_SUCCESS) {
 +//        err = RegSetValueW(hkey, nullptr, REG_SZ, kv.second.c_str(), 0 /* this parameter is ignored */);
 +//        RegCloseKey(hkey);
 +//        if (err == ERROR_SUCCESS) {
 +//            return S_OK;
 +//        }
 +//    }
 +//    return SELFREG_E_CLASS;
 +//}
 +
 +STDAPI DllGetClassObject(CLSID const &clsid, IID const &iid, void **ppv) {
 +    if (clsid != CLSID_Calculator) {
 +        return CLASS_E_CLASSNOTAVAILABLE;
 +    }
 +    
 +    CalculatorClassObject *pCalculatorClass = nullptr;
 +    try {
 +        pCalculatorClass = new CalculatorClassObject;
 +    } catch (...) {
 +        return E_OUTOFMEMORY;
 +    }
 +    
 +    pCalculatorClass->AddRef();
 +    HRESULT hr = pCalculatorClass->QueryInterface(iid, ppv);
 +    pCalculatorClass->Release();
 +    return hr;
 +}
 +
 +STDAPI DllCanUnloadNow() {
 +    if (GetModuleLockCount() == 0) {
 +        return S_OK;
 +    } else {
 +        return S_FALSE;
 +    }
 +}
 +
 +STDAPI DllRegisterServer(void) {
 +    return E_NOTIMPL;
 +    
 +    // ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
 +    // この関数では、レジストリにモジュールの情報を登録します。
 +    // レジストリの操作は、ちょっとしたミスでシステムを破壊してしまう危険が伴います。
 +    // 何が行われるかを完全に理解していない限り実行をしないでください。
 +    // もし試すのであれば、壊れても被害の少ない実験用の環境で試すことを強くおすすめします。
 +    // 必ずトラブルが発生しても復旧できるように復元ポイントを作成しておいてください。
 +    //    
 +    // サンプルをあげておきます。
 +    // 正しく動作することは一切保証できません。
 +    // 不用意に実行しないでください。
 +    // ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
 +    
 +//    LPOLESTR lpstrClsid;
 +//    StringFromCLSID(CLSID_Calculator, &lpstrClsid);
 +//    RegKV clsid = {std::format(L"CLSID\\{}", lpstrClsid), L"Toymath3 Calculator class"};
 +//    RegKV inproc = {std::format(L"CLSID\\{}\\InprocServer32", lpstrClsid), g_wszModulePath};
 +//    RegKV progid = {std::format(L"CLSID\\{}\\ProgId", lpstrClsid), g_wszProgId};
 +//    RegKV hkcrProgid = {std::format(L"{}", g_wszProgId), lpstrClsid};
 +//    RegKV hkcrProgidClsid = {std::format(L"{}\\CLSID", g_wszProgId), lpstrClsid};
 +//    CoTaskMemFree(lpstrClsid);
 +//    
 +//    if (HRESULT hr = RegisterServerWriteRegistry(clsid); FAILED(hr)) {
 +//        return hr;
 +//    }
 +//    if (HRESULT hr = RegisterServerWriteRegistry(inproc); FAILED(hr)) {
 +//        return hr;
 +//    }
 +//    if (HRESULT hr = RegisterServerWriteRegistry(progid); FAILED(hr)) {
 +//        return hr;
 +//    }
 +//    // HKCR\Toymath3.Calculator.1
 +//    if (HRESULT hr = RegisterServerWriteRegistry(hkcrProgid); FAILED(hr)) {
 +//        return hr;
 +//    }
 +//    // HKCR\Toymath3.Calculator.1\CLSID
 +//    if (HRESULT hr = RegisterServerWriteRegistry(hkcrProgidClsid); FAILED(hr)) {
 +//        return hr;
 +//    }
 +//    
 +//    ITypeLib *ptlib;
 +//    HRESULT hr = LoadTypeLib(g_wszModulePath, &ptlib);
 +//    if (SUCCEEDED(hr)) {
 +//        hr = RegisterTypeLib(ptlib, g_wszModulePath, nullptr);
 +//        ptlib->Release();
 +//    }
 +//    return hr;
 +}
 +
 +STDAPI DllUnregisterServer(void) {
 +    return E_NOTIMPL;
 +
 +    // ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
 +    // この関数では、レジストリから登録されているモジュールの情報を削除します。
 +    // レジストリの操作は、ちょっとしたミスでシステムを破壊してしまう危険が伴います。
 +    // 何が行われるかを完全に理解していない限り実行をしないでください。
 +    // もし試すのであれば、壊れても被害の少ない実験用の環境で試すことを強くおすすめします。
 +    // 必ずトラブルが発生しても復旧できるように復元ポイントを作成しておいてください。
 +    //
 +    // サンプルをあげておきます。
 +    // 正しく動作することは一切保証できません。
 +    // 不用意に実行しないでください。
 +    // ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
 +    
 +//    HRESULT hr = UnRegisterTypeLib(LIBID_ToymathLib3, 1, 0, 0, SYS_WIN32);
 +//
 +//    LPOLESTR lpstrClsid;
 +//    StringFromCLSID(CLSID_Calculator, &lpstrClsid);
 +//    std::wstring keyClsid = std::format(L"CLSID\\{}", lpstrClsid);
 +//    std::wstring keyInproc = std::format(L"CLSID\\{}\\InprocServer32", lpstrClsid);
 +//    std::wstring keyProgId = std::format(L"CLSID\\{}\\ProgId", lpstrClsid);
 +//    std::wstring keyHkcrProgid = std::format(L"{}", g_wszProgId);
 +//    std::wstring keyHkcrProgidClsid = std::format(L"{}\\CLSID", g_wszProgId);
 +//    CoTaskMemFree(lpstrClsid);
 +//    
 +//    if (RegDeleteKeyW(HKEY_CLASSES_ROOT, keyHkcrProgidClsid.c_str()) != ERROR_SUCCESS) {
 +//        hr = E_FAIL;
 +//    }
 +//    if (RegDeleteKeyW(HKEY_CLASSES_ROOT, keyHkcrProgid.c_str()) != ERROR_SUCCESS) {
 +//        hr = E_FAIL;
 +//    }
 +//    if (RegDeleteKeyW(HKEY_CLASSES_ROOT, keyProgId.c_str()) != ERROR_SUCCESS) {
 +//        hr = E_FAIL;
 +//    }
 +//    if (RegDeleteKeyW(HKEY_CLASSES_ROOT, keyInproc.c_str()) != ERROR_SUCCESS) {
 +//        hr = E_FAIL;
 +//    }
 +//    if (RegDeleteKeyW(HKEY_CLASSES_ROOT, keyClsid.c_str()) != ERROR_SUCCESS) {
 +//        hr = E_FAIL;
 +//    }
 +//
 +//    return hr;
 +}
 +</file>
 +
 +==== toymath3.idl =====
 +
 +<file cpp>
 +import "unknwn.idl";
 +
 +[object, uuid(1dc508ef-d0eb-420a-b213-dd16aa0dfee0)]
 +interface ICalculator : IUnknown {
 +    HRESULT Add([in] long x, [in] long y, [out, retval] long *result);
 +    HRESULT Sub([in] long x, [in] long y, [out, retval] long *result);
 +    HRESULT Mul([in] long x, [in] long y, [out, retval] long *result);
 +    HRESULT Div([in] long x, [in] long y, [out, retval] long *result);
 +}
 +
 +[
 +    uuid(f90bdc34-89b3-46dd-b262-edf4aba3a935),
 +    lcid(0),
 +    version(1.0),
 +    helpstring("Toymath Library 3")
 +]
 +library ToymathLib3 {
 +    importlib("stdole32.tlb");
 +
 +    [uuid(957E455A-8FD1-4D33-8057-462897B00888)]
 +    coclass Calculator {
 +        [default] interface ICalculator;
 +    }
 +}
 +</file>
 +
 +==== toymath3.rc =====
 +
 +<file>
 +1   TYPELIB "toymath3.tlb"
 +</file>
  

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki