ユーザ用ツール

サイト用ツール


youtube:vba-dll-005

文書の過去の版を表示しています。


Toymath3

作成日: 2023-09-02 (土)

第5回 VBAでCOMを使う

そのうち説明を追記予定。

test_Toymath3.xls

Sheet1 (Sheet1)

<codeprism title=Sheet1 lang=vba el=true> 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 </codeprism>

Toymath3

Makefile

<codeprism title=Makefile lang=makefile el=true> 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

</codeprism>

calculator.h

<codeprism title=calculator.h lang=cpp el=true> #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 </codeprism> ==== calculator.cpp ===== <codeprism title=calculator.cpp lang=cpp el=true> #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; } </codeprism> ==== calculatorclass.h ===== <codeprism title=calculatorclass.h lang=cpp el=true> #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 </codeprism> ==== calculatorclass.cpp ===== <codeprism title=calculatorclass.cpp lang=cpp el=true> #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; } </codeprism> ==== 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

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;
    }
}

toymath3.rc

1   TYPELIB "toymath3.tlb"

youtube/vba-dll-005.1709462493.txt.gz · 最終更新: 2024/03/03 19:41 by freemikan

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