How to properly use INetSharingManager? - c++

I'm a newbie C++ programmer, and using C++ Builder XE3, and I have a good Delphi background, and I'm trying to use INetSharingManager, but it gives me an error message:
E2352 Cannot create instance of abstract class 'INetSharingManager'
this is the code that I use:
INetSharingManager* NSManager = new INetSharingManager();
My questions are:
How to properly use INetSharingManager in C++?
and how to use INetSharingManager in Delphi, (if it's possible)?
and thanks in advance.

This is an interface, and you cannot instantiate it like that. Remember that interfaces do not have implementation, so there's clearly no chance at all to instantiate them. You have to instantiate something else that implements the interface.
The C++ sample code here shows how to create one of these guys. Here's the key excerpt:
CoInitialize (NULL);
// init security to enum RAS connections
CoInitializeSecurity (NULL, -1, NULL, NULL,
RPC_C_AUTHN_LEVEL_PKT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE, NULL);
INetSharingManager * pNSM = NULL;
HRESULT hr = ::CoCreateInstance (__uuidof(NetSharingManager),
NULL,
CLSCTX_ALL,
__uuidof(INetSharingManager),
(void**)&pNSM);
This code comes from the official Microsoft documentation for this library. You should read that documentation thoroughly.
You ask how to use this interface from Delphi. Well, you do exactly the same as you do in C++. Call CoCreateInstance to obtain an interface reference. Now that you can see how to do it from C++, it's simple enough to translate it to Delphi.

As the answer is fairly outdated I recommend following code:
HRESULT hr = E_FAIL;
CoInitialize(nullptr);
INetSharingManager* pNetSharingManager = nullptr;
hr = CoCreateInstance(CLSID_NetSharingManager,
nullptr,
CLSCTX_ALL,
IID_INetSharingManager,
reinterpret_cast<LPVOID*>(&pNetSharingManager));
Tested and working code sample.

Related

How can I create a JavaScript object in Internet Explorer from C++

I'm using an external C++ application to control Internet Explorer (version is 11, but that seems unimportant for this example). Part of this control is being able to run arbitrary JavaScript in the browser's context. To enable that control, I'd like to be able to create a JavaScript object (or array, or function, etc.), represented by an appropriate IDispatch variant, that I can use in subsequent script calls. There are some examples online, including some from Microsoft, that would indicate such a thing should be possible, by finding and invoking the Object constructor.
Below is some sample code, cribbed from the aforementioned examples, that should do the trick. However, when I execute the code, I get an E_INVALIDARG ("One or more arguments are invalid") HRESULT returned. What am I doing wrong, and how do I fix the issue?
// Example assumes that you're using an ATL project which give access to
// the "CCom" wrapper classes, and that you have the ability to retrieve
// an IHTMLDocument2 object pointer.
int CreateJavaScriptObject(IHTMLDocument2* script_engine_host, CComVariant* created_object) {
// NOTE: Proper return code checking and error handling
// has been omitted for brevity
int status_code = 0;
CComPtr<IDispatch> script_dispatch;
HRESULT hr = script_engine_host->get_Script(&script_dispatch);
CComPtr<IDispatchEx> script_engine;
hr = script_dispatch->QueryInterface<IDispatchEx>(&script_engine);
// Create the variables we need
DISPPARAMS no_arguments_dispatch_params = { NULL, NULL, 0, 0 };
CComVariant created_javascript_object;
DISPID dispatch_id;
// Find the javascript object using the IDispatchEx of the script engine
std::wstring item_type = L"Object";
CComBSTR name(item_type.c_str());
hr = script_engine->GetDispID(name, 0, &dispatch_id);
// Create the jscript object by calling its constructor
// The below InvokeEx call returns E_INVALIDARG in this case
hr = script_engine->InvokeEx(dispatch_id,
LOCALE_USER_DEFAULT,
DISPATCH_CONSTRUCT,
&no_arguments_dispatch_params,
&created_javascript_object,
NULL,
NULL);
*created_object = created_javascript_object;
return status_code;
}
Potential answerers desiring a fully compilable solution can find a version of the above code in a GitHub repo. The repo includes a Visual Studio 2017 solution that creates a console application which will reproduce the issue, including launching Internet Explorer and obtaining a reference to the required IHTMLDocument2 object. Note that the version in the repo has somewhat more complete error handling than the above sample, in which it was omitted for brevity.

In Which Library IFileDialog is Located

Now I'm Writing This Code
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
after Compiling an Error Appeared; "IFileDialog Not Declared in this Scope"
What is The Library of that Class ??
You don't need to know which library implements it. This is a COM interface that you invoke with a call to CoCreateInstance. The system does the rest. It looks up the implementing COM server in the COM registry and instantiates your object.
In order to compile you just need to include Shobjidl.h, and define the version macros appropriately. You need
#define _WINNT_WIN32 0600

C# COM dll has REGDB_E_CLASSNOTREG error in C++ project

I have a C# dll that I properly have registered for COM Interop, and made COM visible. Using cppbuilder, I imported the type library, which generated the wrapper classes, and I am now attempting to use to create an instance of my C# class. However, I'm getting a REGDB_E_CLASSNOTREG error in my C++ code. I verified the dll is in the registry, and even re-registered it with regasm. No change. What could I be missing?
Here is my C++ code:
_MyClassPtr obj;
HRESULT hr = obj.CreateInstance(__uuidof(MyClass));
//now hr equals REGDB_E_CLASSNOTREG
I've also tried it as such:
IMyClass* obj;
HRESULT hr = CoCreateInstance(__uuidof(MyClass), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMyClass), (void**) &obj);
//same result, hr equals REGDB_E_CLASSNOTREG
I do have one additional dependency in the C# app. I registered it for COM as well with no difference, but did not import it's type library into the C++ project.
UPDATE: based on the comments below, I discovered that CreateInstance is looking up the class guid in the following places in the registry:
HKCU\Software\Classes\Wow6432Node\CLSID\{guid}
HKCR\Wow6432Node\CLSID\{guid}
HKCU\Software\Classes\CLSID\{guid}
HKCR\CLSID\{guid}
But, going through the registry, the only entry under any of the CLSID nodes that is related to my assembly is the guid for the assembly itself, which is, of course, different than the guid for the class, or the interface.
I've manually run regasm under both x86 and x64 mode to try to acheive different results. No differences.
Well, I found out what would work.
IMyClassPtr obj;
HRESULT hr = obj.CreateInstance(CLSID_MyClass);
CLSID_MyCLass was a guid constant in the generated MyClass_TLB.cpp file. Using it instead of __uuidof(...) for the class types enabled everything to start working correctly.

OLE automation problems with C++ - "Class not registered"

I'm trying to port a LabView program to C++, and the OLE calls it contains are giving me some trouble.
The LabView program starts out by doing an "Automation open", i.e. getting a reference to the interface "XLib.XInterface" (LabView calls this expression the "ActiveX class"), then calls the method QA found in the interface and finally closes the reference again. I think LabView gets its info on the interface from the type library, but I'm not entierly sure.
I've tried to adapt some code for Word automation I found: http://www.codeproject.com/KB/office/MSOfficeAuto.aspx
CoInitialize(NULL);
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"XConfig.XInterface", &clsid);
IDispatch *pWApp;
if(SUCCEEDED(hr))
{
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch, (void **)&pWApp);
}
// etc.
The program is successful in looking up the CLSID, but CoCreateInstance fails, claiming that the class is not registered. I've also tried entering the CLSID from the type library directly, bypassing CLSIDFromProgID, but yielding the same result. Needless to say that the LabView program works fine, and the C++ code I'm using has no trouble at all to create an instance of Word when using the progID "Word.Application". The interface in question looks like this:
[
odl,
uuid(33AAA2DA-70EB-48EE-ACA7-DD0D1F5CAF2D),
helpstring("XInterface Interface"),
dual,
oleautomation
]
interface XInterface : IDispatch {
[id(0x00000001), helpstring("method QA")]
HRESULT QA();
[id(0x00000002), helpstring("method LoadFromDisk")]
HRESULT LoadFromDisk();
...
As you may have noticed, OLE is kind of new to me (most likely, that's a part of the problem). Any hints would be greatly appreciated. Thanks.
OK, I think I figured it out by myself, even though I don't fully understand my solution. Anyway, when I use
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch,
(void **)&pWApp);
it seems to work; at least I don't get the "class not registered" error anymore. The difference is replacing the argument CLSCTX_LOCAL_SERVER with CLSCTX_ALL. I think it's got something to do with the fact that I'm using a dll. Does anyone have a more insightful explaination?

How to use msxml with Visual Studio 2008 Express (no ATL classes) without becoming crazy?

It is not really a question because I have already found a solution. It took me a lot of time, that's why I want to explain it here.
Msxml is based on COM so it is not really easy to use in C++ even when you have helpful classes to deal with memory allocation issues. But writing a new XML parser would be much more difficult so I wanted to use msxml.
The problem:
I was able to find enough examples on the internet to use msxml with the help of CComPtr (smart pointer to avoid having to call Release() for each IXMLDOMNode manually), CComBSTR (to convert C++ strings to the COM format for strings) and CComVariant. This 3 helpful classes are ATL classes and need an #include <atlbase.h>.
Problem: Visual Studio 2008 Express (the free version) doesn't include ATL.
Solution:
Use comutil.h and comdef.h, which include some simple helper classes:
_bstr_t replaces more or less CComBSTR
_variant_t replaces more or less CComVariant
_com_ptr_t replaces indirectly CComPtr through the use of _COM_SMARTPTR_TYPEDEF
Small example:
#include <msxml.h>
#include <comdef.h>
#include <comutil.h>
// Define some smart pointers for MSXML
_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument, __uuidof(IXMLDOMDocument)); // IXMLDOMDocumentPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMElement, __uuidof(IXMLDOMElement)); // IXMLDOMElementPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNodeList, __uuidof(IXMLDOMNodeList)); // IXMLDOMNodeListPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNamedNodeMap, __uuidof(IXMLDOMNamedNodeMap)); // IXMLDOMNamedNodeMapPtr
_COM_SMARTPTR_TYPEDEF(IXMLDOMNode, __uuidof(IXMLDOMNode)); // IXMLDOMNodePtr
void test_msxml()
{
// This program will use COM
CoInitializeEx(NULL, COINIT_MULTITHREADED);
{
// Create parser
IXMLDOMDocumentPtr pXMLDoc;
HRESULT hr = CoCreateInstance(__uuidof (DOMDocument), NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc);
pXMLDoc->put_validateOnParse(VARIANT_FALSE);
pXMLDoc->put_resolveExternals(VARIANT_FALSE);
pXMLDoc->put_preserveWhiteSpace(VARIANT_FALSE);
// Open file
VARIANT_BOOL bLoadOk;
std::wstring sfilename = L"testfile.xml";
hr = pXMLDoc->load(_variant_t(sfilename.c_str()), &bLoadOk);
// Search for node <testtag>
IXMLDOMNodePtr pNode;
hr = pXMLDoc->selectSingleNode(_bstr_t(L"testtag"), &pNode);
// Read something
_bstr_t bstrText;
hr = pNode->get_text(bstrText.GetAddress());
std::string sSomething = bstrText;
}
// I'm finished with COM
// (Don't call before all IXMLDOMNodePtr are out of scope)
CoUninitialize();
}
Maybe try using the #import statement.
I've used it in a VS6 project I have hanging around, you do something like this (for illustrative purposes only; this worked for me but I don't claim to be error proof):
#import "msxml6.dll"
...
MSXML2::IXMLDOMDocument2Ptr pdoc;
HRESULT hr = pdoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
if (!SUCCEEDED(hr)) return hr;
MSXML2::IXMLDOMDocument2Ptr pschema;
HRESULT hr = pschema.CreateInstance(__uuidof(MSXML2::DOMDocument60));
if (!SUCCEEDED(hr)) return hr;
pschema->async=VARIANT_FALSE;
VARIANT_BOOL b;
b = pschema->loadXML(_bstr_t( /* your schema XML here */ ));
MSXML2::IXMLDOMSchemaCollection2Ptr pSchemaCache;
hr = pSchemaCache.CreateInstance(__uuidof(MSXML2::XMLSchemaCache60));
if (!SUCCEEDED(hr)) return hr;
_variant_t vp=pschema.GetInterfacePtr();
pSchemaCache->add(_bstr_t( /* your namespace here */ ),vp);
pdoc->async=VARIANT_FALSE;
pdoc->schemas = pSchemaCache.GetInterfacePtr();
pdoc->validateOnParse=VARIANT_TRUE;
if (how == e_filename)
b = pdoc->load(v);
else
b = pdoc->loadXML(bxmldoc);
pXMLError = pdoc->parseError;
if (pXMLError->errorCode != 0)
return E_FAIL; // an unhelpful return code, sigh....
Another option would to use another XML parser that is already done, such as eXpat. It avoids having to use ATL and the complexities of COM, and is way easier than implementing your own. I suggest this only becasue you've stated that the reason you're looking at msxml is because you don't want to implement your own parser.
You can use TinyXML. It is open source and more over platform independent.
I'm happy I posted my question although I already had a solution because I got several alternative solutions. Thanks for all your answers.
Using another parser such as eXpat or the maybe smaller (not so powerfull but enough for my needs) TinyXML could actually be a good idea (and make it easier to port the program to another operating system).
Using an #import directive, apparently a Microsoft specific extension to simplify the use of COM, is also interesting and brought me to the following web page MSXML in C++ but as elegant as in C#, which explain how to simplify the use of msxml as much as possible.
Why don't you use some MSXML wrapper that would shield you form COM, such as Arabica?