What is the equivalent for win32com.client.GetObject() in CPP? - c++

What is the equivalent for win32com.client.GetObject() in CPP ?
I am trying to get the SAPGUI object in CPP
SapGuiAuto = win32com.client.GetObject("SAPGUI")
Referring to these quotes from the below article - https://blogs.sap.com/2020/08/02/sap-gui-scripting-api-from-the-past-for-future-automation/
The SAP GUI Scripting API is in the file sapfewse.ocx (FEWSE = Front End Windows Scripting Engine), in the directory C:\Program Files (x86)\SAP\FrontEnd\SapGui. It is a Component Object Model (COM) library and registered in the Windows registry. On this way you can use it from any COM-enabled programming language

There is no "C++" way of doing it. There are, however, ways of doing it on Windows using Microsoft libraries.
I'd recommend using CComDispatchDriver class. Haven't tested this...but it will get you close.
// .. include standard windows stuff
#include <comdef.h>
#include <atlbase.h>
class ComInit
{
public:
ComInit()
{
CoInitialize(NULL);
}
~ComInit()
{
CoUnintialize();
}
ComInit(const ComInit& ) = delete;
ComInit& operator=(const ComInit&) = delete;
};
int main(int argc, char* argv)
{
ComInit _cominit;
CComDispatchDriver disp;
disp.CoCreateInstance(L"Excel.Application");
_variant_t vName;
disp.GetPropertyByName(L"Name", &vName);
return 0;
}

Related

Dealing with Class Ambiguity without changing the library code

I have a C++ code that links two shared libraries (let's say, foo1.so and foo2.so). In both libraries I have a class called "Mesh", and the compiler cannot know which one I am trying to use when I try to instantiate the class Mesh (obviously I know which one I want to instantiate). I get the "error: reference to ‘Mesh’ is ambiguous"
Of course I could alter the source code of one of the libraries, wrapping the Mesh class around a namespace and that would solve the problem. I would like to avoid changing the library's code, though. Is there a way to remove this ambiguity in the source file which uses the libraries?
Thank you,
Rafael.
By using dynamic libs (.so in linux), you can load each one and use each handle to differentiate call.
See Dynamically Loaded (DL) Libraries
For example :
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
class Meshib
{
void * _handle;
double (*_cosine)(double);
public:
Meshib( const char * libraryPath)
{
char *error;
_handle = dlopen (libraryPath, RTLD_LAZY);
if (!_handle) {
fputs (dlerror(), stderr);
exit(1);
}
_cosine = reinterpret_cast<decltype(_cosine)>( dlsym(_handle, "cosine") );
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
}
~Meshib() {
dlclose(_handle);
}
double cosine(double v) { return (*_cosine)(v); }
};
int main(int argc, char **argv)
{
Meshib meshLib1( "foo1.so" );
Meshib meshLib2( "foo2.so" );
printf("%f\n", meshLib1.cosine(2.0));
printf("%f\n", meshLib2.cosine(2.0));
}
See this article for C++ class dynamic load.

MFC C++ static library linked with non MFC console app

I'm trying to compile a console program that uses a static library implementing CString.The console app has been created with the VS wizard with :
Win32 console application with precompiled headers, SDL verification but without ATL or MFC.
The static library is a MFC static library (wizard construction).
Where is (are) my mistake(s) ?
This is what I so long have tried:
I've created a new console app using MFC controls - this compile fine with the static library.
Then I've controlled and modified when necessary every link options, comparing the 2 console projects.
But the 1st console application does not compile.
I'm stucked !
I'm working with Visual Studio 2012 on Windows 10.
Here is the code :
File TestLib.h
#pragma once
#include <atlstr.h>
class TestLib
{
public:
TestLib(){};
TestLib(const CString &tst);
virtual ~TestLib(void);
private:
CString _tst;
};
Fichier TestLib.cpp
#include "stdafx.h"
#include "TestLib.h"
TestLib::TestLib(const CString &tst)
: _tst(tst)
{
}
TestLib::~TestLib(void)
{
}
Fichier ConsoleTest2.cpp
// ConsoleTest2.cpp : définit le point d'entrée pour l'application console.
#include "stdafx.h"
#include "TestLib.h"
int _tmain(int argc, _TCHAR* argv[])
{
TestLib *tst = new TestLib(); // This compile fine !
//TestLib *tst = new TestLib(_T("Test")); // This generates LNK2019 link error
return 0;
}
Here is the solution, thanks to Jochen Arndt
Just have to change the TestLib declaration to
TestLib::TestLib(LPCTSTR str)
: _tst(str)
{
}

CreatePushNotificationChannelForApplicationAsync in native C++

I'm trying to use windows push notifications in native C++ code. But I struggle with implementation. I'm calling CreatePushNotificationChannelForApplicationAsync but it returns
HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : Element not found.
My OS is Win10 and I use Visual Studio 2015.
Here is my code:
#include <wrl.h>
#include <windows.networking.pushnotifications.h>
#include <ppltasks.h>
#pragma comment(lib, "runtimeobject.lib")
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Networking::PushNotifications;
using namespace concurrency;
int main(char* argv[], int argc)
{
RoInitializeWrapper init(RO_INIT_MULTITHREADED);
if ( FAILED(init) )
return 0;
ComPtr<IPushNotificationChannelManagerStatics> channelManager;
HRESULT hr = GetActivationFactory(HStringReference(L"Windows.Networking.PushNotifications.PushNotificationChannelManager").Get(), &channelManager);
if ( FAILED(hr) )
return 0;
IAsyncOperation<PushNotificationChannel*>* asyncOp;
hr = channelManager->CreatePushNotificationChannelForApplicationAsync(&asyncOp); // return HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
if ( FAILED(hr) )
return 0;
// create task to obtain uri from asyncOp
return 0;
}
On the other hand it is pretty straightforward in WinRT.
namespace WnsPushAPI
{
public ref class WnsWrapper sealed
{
public:
void ObtainUri()
{
IAsyncOperation<PushNotificationChannel^>^ channelOperation = PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync();
auto channelTask = create_task(channelOperation);
channelTask.then([this](PushNotificationChannel^ channel) {
// ... Save URI for latter use. channel->Uri->Data()
channel->PushNotificationReceived += ref new TypedEventHandler<PushNotificationChannel^, PushNotificationReceivedEventArgs^>(this, &WnsWrapper::OnNotify);
}, task_continuation_context::use_current());
}
void OnNotify(PushNotificationChannel^ sender, PushNotificationReceivedEventArgs^ e)
{
// do something
};
};
}
I also checked generated code with /d1ZWtokens compiler switch but I didn't find anything useful.
Documentation for push notification for native C++ is really poorly written and I couldn't find and example in native C++.
Your code is okay. The problem lies in the fact that you can only register for push notifications from Windows Store applications. You cannot do that from desktop applications. The error comes from the fact that the system cannot find your AppX package identity.
I also faced same HRESULT_FROM_WIN32(ERROR_NOT_FOUND) error while trying to use WNS from my desktop app. Just in case anyone also faces this issue I'd like to mention CreatePushNotificationChannelForApplicationAsync works fine from Desktop Bridge. Here is the code that I used. Note it is winrt based, and I think WRL based code also would work without any problem, just need to wrap desktop app with Desktop Bridge.
winrt::init_apartment();
PushNotificationChannelManagerForUser manager = PushNotificationChannelManager::GetDefault();
IAsyncOperation<PushNotificationChannel> async = manager.CreatePushNotificationChannelForApplicationAsync();
async.Completed([](auto && result, auto && status) {
auto channel = result.GetResults();
});

Use C++/CLI Library in C++ native code and how to link

I want to use some code that executes a http-post, and because I'm not too familiar with c++ and what libraries you can use, and I am probably too dumb to get libcurl and curlpp to work, I found a link explaining how to use the .net version.
Alright so I created a class. Header File:
public ref class Element
{
public:
Element();
virtual ~Element();
void ExecuteCommand();
};
Class file:
#include "Element.h"
Element::Element()
{
}
Element::~Element()
{
Console::WriteLine("deletion");
}
void Element::ExecuteCommand(){
HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create("http://www.google.com"));
request->MaximumAutomaticRedirections = 4;
request->MaximumResponseHeadersLength = 4;
request->Credentials = gcnew NetworkCredential("username", "password", "domain");
HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());
Console::WriteLine("Content length is {0}", response->ContentLength);
Console::WriteLine("Content type is {0}", response->ContentType);
// Get the stream associated with the response.
Stream^ receiveStream = response->GetResponseStream();
// Pipes the stream to a higher level stream reader with the required encoding format.
StreamReader^ readStream = gcnew StreamReader(receiveStream, Encoding::UTF8);
Console::WriteLine("Response stream received.");
Console::WriteLine(readStream->ReadToEnd());
response->Close();
readStream->Close();
}
If I set the configuration type of this project to Application (exe), and create a new .cpp file where I create an Instance of this Element it works fine.
But my question is: Is it possible to create a .dll/.lib Library from this project and use it in a C++ project without CLI? (I don't want to use ^ for pointers :( )
Even if it's not possible, I have another problem.
When I link the library in a C++/CLI project. I get
unresolved token (06000001) Element::.ctor
unresolved token (06000002) Element::~Element
unresolved token (06000003) Element::ExecuteCommand
3 unresolved externals
the code for main.cpp in the second project is just the following:
#include <Element.h>
int main(){
return 0;
}
Thank you
As Hans Passant already stated: you must compile your C++/CLI code as Dynamic Library in order to be able to consume it from an unmanaged application. CLI/Managed code cannot run from/cannot reside in static libraries.
If you change the C++/CLI library target from Static library to Dynamic library you'll be able to compile successfully your unmanaged C++ application.
One thought from my side:
I think you'll be better if you use mixed mode C++/CLI DLLs to consume the managed functionality - you'll be able to free your consumer application completely from referencing the CLR.
The Header of such mixed mode Wrapper for your Element class would look like this:
#pragma once
#pragma unmanaged
#if defined(LIB_EXPORT)
#define DECLSPEC_CLASS __declspec(dllexport)
#else
#define DECLSPEC_CLASS __declspec(dllimport)
#endif
class ElementWrapperPrivate;
class __declspec(dllexport) ElementWrapper
{
private:
ElementWrapperPrivate* helper;
public:
ElementWrapper();
~ElementWrapper();
public:
void ExecuteCommand();
};
And the implementation would look like this:
#include "ElementWrapper.h"
#pragma managed
#include "Element.h"
#include <msclr\auto_gcroot.h>
using namespace System::Runtime::InteropServices;
class ElementWrapperPrivate
{
public:
msclr::auto_gcroot<Element^> elementInst; // For Managed-to-Unmanaged marshalling
};
ElementWrapper::ElementWrapper()
{
helper = new ElementWrapperPrivate();
helper->elementInst = gcnew Element();
}
ElementWrapper::~ElementWrapper()
{
delete helper;
}
void ElementWrapper::ExecuteCommand()
{
helper->elementInst->ExecuteCommand();
}
Then just compile your Element.cpp + ElementWrapper.cpp to a DLL and use the ElementWrapper.h in your unmanaged applications.

What can I do about loading this resource into a unit testing DLL?

I just ported all of my tests from Google Test to Visual Studio 2012's unit test framework. (Long story; Google's assertions are better but Microsoft's works with the Dev11 Unit Test Explorer out of the box, which makes getting code coverage really easy ...)
I got everything ported over fine, except for the following class, which reads a newline-delimited text file from a Win32 resource, and then allows for quick lookups against that resource:
#include "pch.hpp"
#include "resource.h"
#include <functional>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <windows.h>
#include "Win32Exception.hpp"
#include "Whitelist.hpp"
using Instalog::SystemFacades::Win32Exception;
namespace Instalog {
Whitelist::Whitelist( __int32 whitelistId , std::vector<std::pair<std::wstring, std::wstring>> const& replacements )
{
using namespace std::placeholders;
HRSRC resourceHandle = ::FindResource(0, MAKEINTRESOURCEW(whitelistId), L"WHITELIST");
if (resourceHandle == 0)
{
Win32Exception::ThrowFromLastError();
}
HGLOBAL resourceGlobal = ::LoadResource(0, resourceHandle);
if (resourceGlobal == 0)
{
Win32Exception::ThrowFromLastError();
}
void * resourceData = ::LockResource(resourceGlobal);
if (resourceData == 0)
{
Win32Exception::ThrowFromLastError();
}
wchar_t const* resourceDataCasted = static_cast<wchar_t const*>(resourceData);
DWORD resourceLen = ::SizeofResource(0, resourceHandle);
auto sourceRange = boost::make_iterator_range(resourceDataCasted, resourceDataCasted + (resourceLen / sizeof(wchar_t)));
boost::algorithm::split(innards, sourceRange, std::bind1st(std::equal_to<wchar_t>(), L'\n'));
std::for_each(innards.begin(), innards.end(), std::bind(boost::algorithm::to_lower<std::wstring>, _1, std::locale()));
std::for_each(innards.begin(), innards.end(), [&replacements] (std::wstring &a) {
std::for_each(replacements.begin(), replacements.end(), [&a] (std::pair<std::wstring, std::wstring> const&b) {
if (boost::algorithm::starts_with(a, b.first))
{
a.replace(a.begin(), a.begin() + b.first.size(), b.second);
}
});
});
std::sort(innards.begin(), innards.end());
}
bool Whitelist::IsOnWhitelist( std::wstring checked ) const
{
boost::algorithm::to_lower(checked);
return std::binary_search(innards.begin(), innards.end(), checked);
}
void Whitelist::PrintAll( std::wostream & str ) const
{
std::copy(innards.begin(), innards.end(), std::ostream_iterator<std::wstring, wchar_t>(str, L"\n"));
}
}
Unfortunately, Dev11's test projects generate DLLs, not EXEs, as under Google Test's system. So, while before I was able to embed the resource into the EXE and pass NULL to FindResource's first parameter, now Visual Studio is loading the DLL into its process during testing. Visual Studio certainly doesn't have my custom WHITELIST resource type inside, so this code blows up.
Is there some way I can either
Tell this code somehow to look in the right binary, either the testing DLL or the EXE, depending on context? (Currently this code is in a static library which gets linked with both the real EXE and the testing DLL) or
Embed relatively large (a few MB) text files into a C++ program cleanly without using the Win32 resource infrastructure at all?
It should be noted that putting the resource into a satellite DLL (which might have been a reasonable solution) is not an option; a requirement of this project is single EXE xcopy deployment.
Figured it out. I used the GetCurrentModule hack here -> How do I get the HMODULE for the currently executing code? . This gave the the HMODULE I needed to pass into the XxxResource APIs.