Reputation: 23
I have a need for a COM object that generates a GUID. I am a C# developer, but this will be deployed in a unix environment, so I'm thinking I need to build it in C++. This is my first Visual C++ project, and I'm having some trouble finishing it out.
Steps I've taken:
Created a new ATL project in Visual Studio (Dynamic-link library - no other options)
Right-click project -> Add class -> ATL Simple Object (Short name: GuidGenerator; ProgID: InfaGuidGenerator)
View -> ClassView -> IGuidGenerator -> Add Method (Method Name: Generate; Parameter Type: BSTR* [out]; Parameter Name: retGuid)
Added Boost to get the platform independent UUID generator.
// GuidGenerator.cpp : Implementation of CGuidGenerator
#include "stdafx.h"
#include "GuidGenerator.h"
#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid.hpp> // uuid class
#include <boost/uuid/uuid_generators.hpp> // generators
#include <boost/uuid/uuid_io.hpp> // streaming operators etc.
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
std::string uuidStr = boost::lexical_cast<std::string>(uuid);
//not really sure what to do from here.
//I've tried to convert to BSTR.
//When I assign the resulting value to retGuid, I often get an error:
//A value of type BSTR cannot be assigned to an entity of type BSTR*
return S_OK;
}
Can anyone provide me some guidance on the next step?
Thanks.
Edit from comments:
I have already tried to convert to BSTR using the following, but I get an error:
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
std::string uuidStr = boost::lexical_cast<std::string>(uuid);
int wslen = ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
uuidStr.data(), uuidStr.length(),
NULL, 0);
BSTR wsdata = ::SysAllocStringLen(NULL, wslen);
::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
uuidStr.data(), uuidStr.length(),
wsdata, wslen);
retGuid = wsdata;
//ERROR: A value of type BSTR cannot be assigned to an entity of type BSTR*
return S_OK;
}
Upvotes: 2
Views: 1214
Reputation: 42984
Assuming that std::string uuidStr
is your string you want to return as BSTR
output parameter, consider code like this:
#include <atlbase.h> // for CComBSTR
#include <atlconv.h> // for CA2W
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
try
{
....
// Convert uuidStr from ASCII to Unicode
CA2W wszUuid( uuidStr.c_str() );
// Build a COM BSTR from the Unicode string
CComBSTR bstrUuid( wszUuid );
// Return the BSTR as output parameter
*retGuid = bstrUuid.Detach();
// All right
return S_OK;
}
//
// Catch exceptions and convert them to HRESULTs,
// as C++ exceptions can't cross COM module boundaries.
//
catch(const CAtlException& ex)
{
return static_cast<HRESULT>(ex);
}
catch(const std::exception& ex)
{
// May log the exception message somewhere...
return E_FAIL;
}
}
Note how a RAII helper class like CA2W
simplifies the conversion from ASCII to Unicode, and CComBSTR
simplifies the management of raw BSTR
s.
Upvotes: 1
Reputation: 1210
This Microsoft article on COM under Unix might help more generally.
As to the next step, a BSTR is not your usual string; .NET hides this complexity from you. A BSTR is a specialised string that's intended to be marshalled across thread/process boundaries.
Have a look at this answer to see how to convert your std::string to a BSTR.
Upvotes: 0