文書の過去の版を表示しています。
目次
Toymath3
test_Toymath3.xls
Sheet1 (Sheet1)
<codeprism title=Sheet1 lang=vba el=true css=full> 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 css=full> 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 css=full> #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 css=full> #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 css=full> #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 css=full> #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 ===== <codeprism title=modulelock.h lang=cpp el=true css=full> #ifndef MOUDLELOCK_H #define MODULELOCK_H #include <objbase.h> void LockModule(); void UnlockModule(); LONG GetModuleLockCount(); #endif MODULELOCK_H </codeprism> ==== modulelock.cpp ===== <codeprism title=modulelock.cpp lang=cpp el=true css=full> #include “modulelock.h” static LONG g_cLocks = 0; void LockModule() { InterlockedIncrement(&g_cLocks); } void UnlockModule() { InterlockedDecrement(&g_cLocks); } LONG GetModuleLockCount() { return g_cLocks; } </codeprism> ==== exports.cpp ===== <codeprism title=exports.cpp lang=cpp el=true css=full> #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; } </codeprism>
toymath3.idl
<codeprism title=toymath3.idl lang=cpp el=true css=full> 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; }
} </codeprism>
toymath3.rc
<codeprism title=toymath3.rc el=true> 1 TYPELIB “toymath3.tlb” </codeprism>