Getting the replica ID of Access database using DAO - c++

I've recently ported an MFC project form VS6 to VS2005. The VS6 project linked ddao35d.lib (DAO 3.5) which is no longer compatible with the 'new' MFC used in VS2005. To get around this I'm now including afxdao.h and changing my database classes from CdbDatabase to CDaoDatabase as recommended by other posts : -
http://www.experts-exchange.com/Programming/Languages/CPP/Q_22465486.html
However, there was a member function in CdbDatabase called GetReplicaID() which is no longer in CDaoDatabase. Does anyone know how to get the replica ID of an Access database using the CDaoDatabase class or otherwise?
Here are the important exerpts from that post: -
"As of Visual C++ .NET, the Visual C++ environment and wizards no longer support DAO (although the DAO classes are included and you can still use them). Microsoft recommends that you use OLE DB Templates or ODBC for new projects. You should only use DAO in maintaining existing applications.
The DAO MFC libraries, including ddao35d.lib, are part of PlatformSDK and are not compatible with the new MFC. You are expected to #include and it will link daouuid.lib."
...
"Adding the and daouuid.lib was the trick. PLUS: changing the declaration of CdbLastOLEError TO CDaoErrorInfo. The CdbLastOLEError is still in , but apparently no longer in the ddao35.lib. Changing to CDaoErrorInfo and linking with the addition of daouuid.lib has corrected the linker error."

I've found the solution.. You can access the DAO directly through the m_pDAODatabase member in the CDaoDatabase class. EG: -
CDaoDatabase dbDatabase;
COleVariant varReplicaID( "", VT_BSTRT );
HRESULT hr;
hr = dbDatabase.m_pDAODatabase->get_ReplicaID(& V_BSTR(&varReplicaID) );
For more details see
http://msdn.microsoft.com/en-us/library/1s0dx3s7.aspx

Related

Can't find COM object from C++, although Guid it's registered

First of all happy new year to everyone, hope you're doing well!
I'm working on a C++ project in which I need to call a C# DLL I created following the first answer of this post. Once I have the DLL, I need to call it from Qt, so by using dumpcpp and the .tlb file generated by regasm, I managed to get the .cpp and .h files to use my classes. Just as a reference, the namespace of the classes is Wrapper, and the main class is Device with guid {DD4A4896-C105-4C60-839B-B18C99C8FE15}.
Once I have the generated files to use the DLL, if I try to create a Wrapper:: Device instance on Qt, I get the following error:
QAxBase::setControl: requested control {dd4a4896-c105-4c60-839b-b18c99c8fe15} could not be instantiated
QAxBase::qt_metacall: Object is not initialized, or initialization failed
It doesn't give any more information, so I tried to check if the guid was stored on the system registry (I used the regasm command explained on the previously quoted post, and It said that it was successful, but you never know). Opening Registry editor and searching for the Guid revealed that it's present at: Computer\HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{DD4A4896-C105-4C60-839B-B18C99C8FE15}, which, as far as I know, is the right route for these guids, and it points to the right DLL.
I though It may be due to some kind ActiveQt problem, and as the previously quoted post explained how to use that DLL from VS C++, I decided to give it a try, using this as an another reference. I've finished with this code, which is supposed to create an instance of my Device object
#include <iostream>
#include <atlstr.h>
#import "C:\Users\javie\Documents\Wrapper\Wrapper\bin\x86\Release\netstandard2.0\Wrapper.tlb" named_guids raw_interfaces_only
inline void TESTHR(HRESULT x) { if FAILED(x) _com_issue_error(x); };
int main()
{
try
{
TESTHR(CoInitialize(0));
Wrapper::IDevicePtr devPtr = nullptr;
TESTHR(devPtr.CreateInstance("{DD4A4896-C105-4c60-839B-B18C99C8FE15}"));
}
catch (const _com_error& e)
{
CStringW out;
out.Format(L"Exception occurred. HR = %lx, error = %s", e.Error(), e.ErrorMessage());
MessageBoxW(NULL, out, L"Error", MB_OK);
}
CoUninitialize();// Uninitialize COM
std::cout << "Hello World!\n";
}
However, this doesn't work either, the createInstance method throws an exception of Class not registered and HR=80040154. Again, according to Registry editor, the class is registered, so I don't understand the error. I've also tried with devPtr.CreateInstance("Wrapper.Device"), devPtr.CreateInstance("Wrapper::Device") or `devPtr.CreateInstance("Wrapper::CLSID_Device") as the links I posted suggest, but in those cases I get another exception with HR=800401f3 and message Invalid class string.
It doesn't matter whether VS or Qt Creator are opened as administrator or not, I get the exact same error.
I have run out of ideas, and I really need to be able to use that DLL from Qt using the files generated by dumpcpp.
Does any one know what could be happening? It feels quite strange to me.
If your C++ application is 64-bit, that's the answer right there, because your C# component is 32-bit (or MSIL but registered to the 32-bit hive). In situations like these, a simple test using VBScript is always useful.
Write a simple VB Script (test.vbs)
Dim obj
Set obj = CreateObject("Wrapper.Device") ' or whatever your ProgID is
MsgBox TypeName(obj)
Now, run this macro 2 ways: with 32-bit and 64-bit versions of VBScript:
32-bit > c:\windows\SysWow64\cscript.exe test.vbs
64-bit > c:\windows\system32\cscript.exe test.vbs
This is assuming your C# component is dispatch compatible. If it's not, then it will still give you differing results that you can use to debug.
Assuming automation/IDispatch compatible, one will work and one won't if you have registered your component correctly.
Have you registered correctly? When I use regasm, I always use the the switches /tlb /codebase when registering the C# component for COM.
Ok, in case someone find the same error, I'll explain the solution I found.
The problem was that in my case, the C# class I developed depended on another 32 bits dll which was not registered on my PC. Once I registered the other dll, everything worked fine.
I don't know why VS kept telling me that the class was not registered when my class itselft was registered, it was one of its dependencies that wasn't registered.
Anyway, I discovered this thanks to Joseph's comments, so thanks a lot for your help.

Adding an automation method to an existing MFC class

I'm using Visual Studio 2019 and I have an MFC application with automation server support. There is an existing class with automation methods...
BEGIN_DISPATCH_MAP(CSizeToolDoc, CDocument)
//{{AFX_DISPATCH_MAP(CSizeToolDoc)
DISP_PROPERTY_EX(CSizeToolDoc, "ClientGetData", GetClientGetData, SetClientGetData, VT_BOOL)
DISP_FUNCTION(CSizeToolDoc, "SetActiveArea", SetActiveArea, VT_BOOL, VTS_VARIANT)
DISP_FUNCTION(CSizeToolDoc, "ShowWindow", ShowWindow, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CSizeToolDoc, "GetBoxes", GetBoxes, VT_VARIANT, VTS_NONE)
...
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
I simply need to add a new automation method but I can't locate any documentation describing how to do this and the Class Wizard doesn't seem to provide it either (if I try to add the code manually I'm worried it will break the app because I don't know all the files which would need to be updated).

Implementing Active Directory with C++ Builder

We want to implement Active Directory using C++ Builder (10.2 Tokyo). I've managed to download the SDK from Microsoft and even used C++ Builder's implib/coff2omf utilities to convert the .Lib files to work with C++ Builder.
I've found some sample code from the Microsoft docs, but now its trying to use a CComBSTR function from Microsoft. As I'm going through this the more I am doubting this is the correct way. Regardless, here's the line:
hr = pCont->Create(CComBSTR("user"), CComBSTR("cn=jeffsmith"), &pDisp );
Is there a better way to approach this?
CComBSTR is a smart wrapper class in the ATL framework for a COM BSTR string. C++Builder officially dropped support for ATL in XE (but you can still use it).
C++Builder's RTL has its own smart wrappers for BSTR (WideString and TOleString), for example:
hr = pCont->Create(WideString("user").c_bstr(), WideString("cn=jeffsmith").c_bstr(), &pDisp );

Can I use all the functionally I see exposed by the .TLH file?

Background:
I have an existing code that uses functionality provided by Microsoft, to post XML data over HTTP. Specifically, IServerXMLHTTPRequest (included in MSXML3 and up) from msxml4.dll (COM). I am moving to msxml6.dll as msxml4.dll is not supported anymore (superseded by MSXML6). More information about MSXML versions.
Code:
#import "msxml6.dll"
using namespace MSXML2;
…
IServerXMLHTTPRequestPtr spIXMLHTTPRequest = NULL;
hr = spIXMLHTTPRequest.CreateInstance(__uuidof(ServerXMLHTTP40));
Problem:
When building my app with msxml4.dll as well as msxml6.dll the following is included in the msxml4.tlh and msxml6.tlh respectively:
struct __declspec(uuid("88d969c6-f192-11d4-a65f-0040963251e5"))
ServerXMLHTTP40;
// [ default ] interface IServerXMLHTTPRequest2
As I understand, looking at msxml6.tlh, I can use ServerXMLHTTP40 (and not change the code to ServerXMLHTTP60) with msxml6.dll (same for DOMDocument40, FreeThreadedDOMDocument40, XMLSchemaCache40 etc.).
Now, searching the registry in a fresh Windows 7 Ultimate installation, I cannot find the uuid above. As a result, this code fails on this machine:
hr = spIXMLHTTPRequest.CreateInstance(__uuidof(ServerXMLHTTP40));
Questions:
If msxml6 is exposing ServerXMLHTTP40, why is it that I cannot find it in the registry? Can I use ServerXMLHTTP40 when msxml6 is installed (msxml4 is not installed)?
Need additional information? Just let me know. Thank you!
.TLH file (as a product of import from .TLB, which is in turn a compiled version of .IDL file) is a description of interfaces, structures, methods etc. which ones uses to talk through COM to another object. There is no guarantee or promise that the other party implementing these interfaces is installed or otherwise available, or even exists at all.
Yes you have the signatures defined for you convenience. You might need to install runtime that implements the functionality. MSXML 4 might need a separate install regardless of where you obtained the development details from.

Problems accessing uccapi.dll COM interface C++

I'm working on a project involving the Microsoft Unified Communications Client API; uccapi.dll. I'm also using Codegear C++Builder 2010, not Visual Studio. After registering the dll with regsvr32 and importing it as type library into C++Builder 2010, uccapi_tlb- and uccapi_ocx-files were generated. When having imported these into my new project I'm trying to follow the msdn guideline for creating a Office Communicator Client able of signing into the Office Communication server.
In this regard I have two questions:
What is the correct way of accessing the com-interfaces made available through the ocx?
I've so far found several ways of creating access points, such as.
TCOMIUccPlatform plat;
plat = CoUccPlatform::Create();
and
IUccPlatformPtr im;
im = CreateComObject(CLSID_UccPlatform);
and
IUccPlatform* pIUccPlatform;
hr = CoCreateInstance(CLSID_UccPlatform,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IUccPlatform),
(void**)&pIUccPlatform);
and
IUccPlatformPtr pIPlat;
pIPlat.CreateInstance(__uuidof(IUccPlatform));
The three first seem to work well. The latter will give me an Assertion failed: intf!=0 error with 0×40000015 exception. Using any of the three top ones I can access methods and initialize the platform interface.
However when trying any of the same tactics to access any other interface, such as IUccContext, IUccUriManager or IUccUri, all of which have a clsid defined in the _tlb.h file, I either get a "class not registered" error in the first two cases, or a hresult failure in the third case. Which brings me to my next question.
Using ole-viewer all interfaces are registered as they should. Why wouldn't all co-creatable classes in the dll be registered when registering the dll? And what could be the reasons why don't they act similarly?
Edit1 from UCCAPILib_tlb.h:
//
// COCLASS DEFAULT INTERFACE CREATOR
// CoClass : UccPlatform
// Interface: TCOMIUccPlatform
//
typedef TCoClassCreatorT<TCOMIUccPlatform, IUccPlatform, &CLSID_UccPlatform, &IID_IUccPlatform> CoUccPlatform;
//
// COCLASS DEFAULT INTERFACE CREATOR
// CoClass : UccUriManager
// Interface: TCOMIUccUriManager
//
typedef TCoClassCreatorT<TCOMIUccUriManager, IUccUriManager, &CLSID_UccUriManager, &IID_IUccUriManager> CoUccUriManager;
This issue is already being discussed in detail in the Embarcadero forums.