我一直在阅读COM和VBScript,现在我很好奇我是否可以使用CoCreateInstance函数从C ++创建一个Scripting.Dictionary对象。
我想要完成的是这样的事情:
script.vbs
' reminder: run with "cscript script.vbs"
Option Explicit
Dim myDictionary
Set myDictionary = CreateObject("Scripting.Dictionary")
myDictionary.Add "Foo", "Bar"
MsgBox myDictionary.Item("Foo")
我实际上并不了解实例化COM对象的过程是如何工作的,但根据我的理解,它必须看起来像:
的main.cpp :
/* reminder: use Unicode */
#include <Windows.h>
#include <stdio.h>
/**
* Takes a guid and dumps it out to stdin as a string.
* @param guid guid to dump to stdin.
*/
void DumpGUID(GUID guid)
{
char dumpData[81];
sprintf_s (
&dumpData[0],
81,
"{"
"\"Data1\": \"%u\","
"\"Data2\": \"%u\","
"\"Data3\": \"%u\","
"\"Data4\": \"%u\""
"}",
guid.Data1,
guid.Data2,
guid.Data3,
guid.Data4
);
puts(dumpData);
}
int main(int argc, char **argv)
{
GUID guid;
const wchar_t *ScriptingDictionaryGUID = L"EE09B103-97E0-11CF-978F-00A02463E06F";
void *myDictionary = NULL;
/* anonymous scope: set guid to 0 so I can tell if it has changed */
{
memset(&guid, 0, sizeof(guid));
}
DumpGUID(guid);
/* anonymous scope: convert my string to guid */
{
HRESULT whyNoConvert = CLSIDFromString((LPCOLESTR)ScriptingDictionaryGUID, &guid);
if (FAILED(whyNoConvert)) {
printf("can't convert string to guid, got error %d.\n", whyNoConvert);
/* ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680589(v=vs.85).aspx */
switch (whyNoConvert) {
case NOERROR:
puts("The CLSID was obtained successfully.");
break;
case CO_E_CLASSSTRING:
puts("The class string was improperly formatted.");
break;
case REGDB_E_CLASSNOTREG:
puts("The CLSID corresponding to the class string was not found in the registry.");
break;
case REGDB_E_READREGDB:
puts("The registry could not be opened for reading.");
break;
}
system("pause");
}
}
DumpGUID(guid);
HRESULT instantiationResult = CoCreateInstance (
guid,
NULL,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
IID_IDispatch,
&myDictionary
);
DumpGUID(guid);
if (FAILED(instantiationResult)) {
puts("Can't create a dictionary :(");
} else {
puts("I HAVE DONE IT!");
}
system("pause");
return 0;
}
我的代码无法创建字典对象(但它确实编译)... 它也无法实际从我的String转换为GUID,错误&#34;类字符串格式不正确。&#34;。
我不知道我做错了什么(或者我正在做的事情)。
编辑:工作代码(一旦创建了对象,仍然需要弄清楚如何与对象进行交互)
#ifndef UNICODE
#define UNICODE
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef STRICT
#define STRICT
#endif
#pragma comment(lib, "uuid.lib")
#pragma comment(lib, "ole32.lib")
#include <windows.h>
#include <stdio.h>
int main(int argc, char **argv)
{
GUID dictionary_guid = {0xEE09B103, 0x97E0, 0x11CF, {0x97, 0x8F, 0x00, 0xA0, 0x24, 0x63, 0xE0, 0x6F}};
IDispatch* p_dictionary = nullptr;
/* anonymous scope: initializing COM */
{
HRESULT result = CoInitialize(NULL);
if (!SUCCEEDED(result)) {
printf("CoInitialize failed: %u.\n", result);
system("pause");
exit(0);
}
}
/* anonymous scope: creating instance and checking */
{
HRESULT result = CoCreateInstance (
dictionary_guid,
nullptr,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
IID_IDispatch,
reinterpret_cast<void**>(&p_dictionary)
);
if (!SUCCEEDED(result)) {
puts("CoCreateInstance failed");
system("pause");
exit(0);
}
puts ("I HAVE DONE IT!");
printf("HRESULT = %u.\n", result);
printf("p_dictionary: %u.\n", p_dictionary);
}
p_dictionary->Release();
CoUninitialize();
system("pause");
return EXIT_FAILURE;
}
提前致谢!
答案 0 :(得分:1)
此代码适用于我:
#undef UNICODE
#define UNICODE
#undef NOMINMAX
#define NOMINMAX
#undef STRICT
#define STRICT
#include <windows.h>
#include <iostream>
#include <stdexcept>
#include <string>
auto fail( std::string const& s )
-> bool
{ throw std::runtime_error( s ); }
struct Succeeded {};
auto operator>>( HRESULT const hr, Succeeded )
-> bool
{ return SUCCEEDED( hr ); } // A macro from <windows.h>.
struct Com_library
{
~Com_library()
{ CoUninitialize(); }
Com_library()
{
CoInitialize( 0 )
>> Succeeded() || fail( "CoInitialize failed" );
}
};
namespace sys {
using String = std::wstring;
auto& out = std::wcout;
auto& err = std::wcerr;
} // namespace sys
void cppmain()
{
Com_library const using_Com;
GUID const dictionary_guid =
{0xEE09B103, 0x97E0, 0x11CF, {0x97, 0x8F, 0x00, 0xA0, 0x24, 0x63, 0xE0, 0x6F}};
IDispatch* p_dictionary = nullptr;
CoCreateInstance (
dictionary_guid,
nullptr,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
IID_IDispatch,
reinterpret_cast<void**>( &p_dictionary )
)
>> Succeeded() || fail( "CoCreateInstance failed" );
sys::out << "I HAVE DONE IT!\n";
/* figure out how to use the dictionary handle */
p_dictionary->Release(); // You want to automate this, e.g. smart pointer.
}
auto main()
-> int
{
using std::exception;
try
{
cppmain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
sys::err << x.what() << "\n";
}
return EXIT_FAILURE;
}
使用g ++进行编译:
g++ com_example.cpp -lole32 -luuid
使用Visual C ++进行编译:
cl com_example.cpp ole32.lib uuid.lib
重要的是要记住通过调用CoInitialize
来初始化COM。另外,请注意直接使用IDispatch
是C ++中的PITA(在脚本语言中非常简单,它的设计,但在C ++中是非常简单的),所以如果字典类支持双接口你最好查询更普通的C ++友好界面。或者使用一些3 rd 方的C ++ IDispatch
包装器,这样可能存在(因为我做了一次,我猜其他人也可能有,并把它放在网上)。
答案 1 :(得分:1)
如果你使用Visual Studio,有一个很酷的#import directive生成包装器,当Type Library可用时,它可以缓解COM。
大多数情况下,类型库包含在COM对象本身(服务于您之后的对象的DLL)中,或者包含在DLL中的.TLB中。下面是一个脚本对象的简单示例,它位于C:\ Windows \ System32 \ scrrun.dll中:
#include "stdafx.h"
// import the .TLB that's compiled in scrrun.dll
#import "C:\Windows\System32\scrrun.dll" \
rename("FreeSpace", "FreeSpace2") // avoid name collision with Windows SDK's GetFreeSpace macro, this is specific to scrrun.dll
using namespace Scripting;
// sample usage of Scripting.Dictionary
void CreateDicAndAdd()
{
IDictionaryPtr ptr(__uuidof(Dictionary)); // create an instance of the Dictionary coclass and get an IDictionary pointer back
_variant_t foo = L"foo";
_variant_t bar = L"bar";
ptr->Add(&foo, &bar); // call the Add method
wprintf(L"%i\n", ptr->Count); // call the Count property (wrapper that was generated automatically)
_variant_t outBar;
ptr->get_Item(&foo, &outBar); // get the item for "foo"
// here we know it's a string (outBar.vt could tell you, in case you didn't know)
// in fact, it's a BSTR, but a BSTR is also a LPWSTR
// (the reverse is false, welcome to Automation :-)
wprintf(L"%s\n", outBar.bstrVal);
}
// sample driver code.
int main()
{
CoInitialize(NULL);
CreateDicAndAdd();
CoUninitialize();
return 0;
}
很酷的是所有这些包装(_variant_t,IDictionaryPtr等)都很聪明,这意味着你不必明确地释放或处理它们。最后,它与使用更高级语言(VBScript,JScript,C#等)编写COM的方式非常相似。