C++ Application That Uses MSI Automation API 32 and 64bit - c++

I am trying to create simple c++ win32 console app(in vs2010) that calls windows installer automation api. But I am failing so far. This approach causes the "Microsoft C++ exception: _com_error at memory location" error.
How to correctly use this api? How to make it work correctly on 32 and 64 bit system with only one .exe file?
Many thanks,
Marek
#include "stdafx.h"
#include <windows.h>
#include <atlstr.h>
#import "msi.dll"
using namespace WindowsInstaller;
_bstr_t GetInstalledProduct(InstallerPtr pInstaller,_bstr_t upgradeCode){
StringListPtr installedProducts = pInstaller->GetRelatedProducts(upgradeCode);
return installedProducts->Count > 0 ? installedProducts->GetItem(0) : "";
}
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
InstallerPtr pInstaller("WindowsInstaller.Installer");
_bstr_t upgradeCode("4C34BD16-CAD4-4059-B074-777793406C5F");
_bstr_t installedProduct = GetInstalledProduct(pInstaller, upgradeCode);
StringListPtr features = pInstaller->GetFeatures(installedProduct);
::CoUninitialize();
return 0;
}

I finally found the solution. The correct way is include msi.lib in linker includes and use Msi.h from windows sdk.
#include "stdafx.h"
#include <windows.h>
#include <Msi.h>
int _tmain(int argc, _TCHAR* argv[])
{
wchar_t productCode[255];
int result = MsiEnumRelatedProducts(L"{4C34BD16-CAD4-4059-A074-777493406C5F}", 0, 0, productCode);
wchar_t featureName[255];
wchar_t featureParent[255];
MsiEnumFeatures(productCode, 0, featureName, featureParent);
INSTALLSTATE featureState = MsiQueryFeatureState(productCode, L"FeatureName");
return 0;
}

Related

"Debug Error! abort() has been called" EASendEmail

I am using EASendEmail with Visual C++. After I compile the code and run it, I get an error which reads: "Debug Error! /Program:[file path] /abort() has been called/ (press retry to debug the application)"
The code is from this website:https://www.emailarchitect.net/easendmail/kb/vc.aspx?cat=0
The error is occurring in the lins:
oSmtp->LicenseCode = _T("TryIt");
'
_tprintf(_T("Start to send email ...\r\n"));
I have tried debugging mode in visual studio and it lead me to an unhandled expression in an attached library and an error at a specific memory location.
c++
#include "pch.h"
#include "easendmailobj.tlh"
#include <tchar.h>
#include <iostream>
using namespace std;
using namespace EASendMailObjLib;
int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
IMailPtr oSmtp = NULL;
oSmtp.CreateInstance("EASendMailObj.Mail");//<- one cause of the error
oSmtp->LicenseCode = _T("TryIt");
//...
_tprintf(_T("Start to send email ...\r\n"));//<- one cause of the error
the error:https://imgur.com/a/M3C72Kc

I invoke LSCopyApplicationURLsForURL() using C++, but get a segment fault

I want to write a C++ program to get associated applications which are suitable to open specified file. I find the LSCopyApplicationURLsForURL API, and create a command line C++ application by XCode.
But after running this program, I always get segment fault. XCode shows EXEC_BAD_ACCESS(code=1, address....) error.
I also tryied running it from sudo, but the same result. What is the problem?
The code:
#include <iostream>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
using namespace std;
int main(int argc, const char * argv[]) {
auto url = CFURLRef("file:///Users/efan/src/a.cpp");
auto ret = LSCopyApplicationURLsForURL(url, kLSRolesAll);
cout << ret << endl;
return 0;
}
Try creating your CFURLRef using one of the proper CFURLCreate* methods. See "Creating a CFURL" here.
For example:
auto tempStringURL = CFStringCreateWithCString(nullptr, "/Users/efan/src/a.cpp", kCFStringEncodingUTF8);
auto url = CFURLCreateWithFileSystemPath(nullptr, tempStringURL, kCFURLPOSIXPathStyle, FALSE);
auto ret = LSCopyApplicationURLsForURL(url, kLSRolesAll);
You need to Release the "Created" variables to clean up memory.

import a certificate using CryptUIWizImport automatically as a trusted root with C++

I am using the following code to import a certificate as a trusted root:
#include "stdafx.h"
#include "windows.h"
#include "Cryptuiapi.h"
#pragma comment(lib, "Cryptui.lib")
int _tmain(int argc, _TCHAR* argv[]){
CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
memset(&importSrc, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
importSrc.dwSize = sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
importSrc.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
importSrc.pwszFileName = L“C:\\PathToCert\\MyCertificate.cer”;
importSrc.pwszPassword = L"";
importSrc.dwFlags = CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED;
if (CryptUIWizImport(
CRYPTUI_WIZ_NO_UI,
NULL,
NULL,
&importSrc,
NULL
) == 0)
{
printf(“CryptUIWizImport error 0x%x\n”, GetLastError());
}
return 0;
}
However, this approach imports my certificate as a Intermediate Certificate Authorities while I need to import it as a Trusted Root Certificate Authorities. I do not want to use any wizard approach and I can not change my certificate.
Is it possible to import this certificate as a trusted root?
Is there any property in CryptUIWizImport to set the certificate type as the trusted root?
Thanks in advances
We should execute a batch file command from inside the C++ code:
#include "stdafx.h";
#include "windows.h"
#include "Cryptuiapi.h"
#include <iostream>
#include <string>
using namespace std;
#pragma comment(lib,"Cryptui.lib")
int _tmain(int argc, _TCHAR* argv[])
{
char buffer[MAX_PATH];
GetModuleFileNameA(NULL, buffer, MAX_PATH);
string::size_type pos = string(buffer).find_last_of("\\/");
string myPath = string(buffer).substr(0,pos);
string myCommand = "certutil -addstore -f -enterprise -user root \""+myPath+"\\IRIPO CA.cer\"";
system(myCommand.c_str());
return 0;
}
Note that the certificate file should be put next to the exe file.

CImage::Load can't load an image

I write code as direction on MSDN, but it doesn't work. It can't load an image and save an image as bmp.
#include "stdafx.h"
#include "atlimage.h"
#include "cstdio"
#include "fstream"
int _tmain(int argc, _TCHAR* argv[])
{
CImage m_image1;
CImage m_image2;
char *srcFile = "C:\\Users\\TYZRPVX\\Desktop\\test.jpg";
const char *tarFile = "C:\\Users\\TYZRPVX\\Desktop\\testBmp.bmp";
FILE *tar;
fopen_s(&tar, tarFile, "w");
m_image1.Load((LPCTSTR)(srcFile));
//m_image1.Save(_T("C:\\Users\\TYZRPVX\\Desktop\\testBmp.bmp"));
m_image1.Save(_T("C:\\Users\\TYZRPVX\\Desktop"),Gdiplus::ImageFormatBMP);
return 0;
}
You're probably compiling with Unicode enabled which the default when creating a new project in Visual Studio. This makes your cast to LPCTSTR incorrect. Use wide character strings for your filenames and drop the cast.
const wchar_t *srcFile = L"C:\\Users\\TYZRPVX\\Desktop\\test.jpg";
const wchar_t *bmpFile = L"C:\\Users\\TYZRPVX\\Desktop\\testBmp.bmp";
m_image1.Load(srcFile);
m_image1.Save(bmpFile, Gdiplus::ImageFormatBMP);

NetUserChangePassword C++

I would like to change user password on my Windows 7 PC using C++.
But when I compile it gets error:
undefined reference to 'NetUserChangePassword'
[Error] ld returned 1 exit status.`
How can I fix it?
Here is the MSDN page with the NetUserChangePassword function:
#ifndef UNICODE
#define UNICODE
#endif
#pragma comment(lib, "netapi32.lib")
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <lm.h>
bool ChangeUserPassword(LPCWSTR OldPassword, LPCWSTR NewPassword)
{
NET_API_STATUS nStatus;
LPTSTR lp = new TCHAR[256];
DWORD dw = 256;
GetUserName(lp, &dw);
nStatus = NetUserChangePassword(NULL, lp, OldPassword, NewPassword);
delete[] lp;
if (nStatus == NERR_Success)
return true;
return false;
}
int main(int argc, char** argv)
{
LPCWSTR Old_P = L"C";
LPCWSTR New_P = L"D";
ChangeUserPassword(Old_P, New_P);
return 0;
}
I tried to link to the project the winapi32.dll in two ways
i tried to add using the project option
i tried to add following line
HINSTANCE hInst = LoadLibrary( L"C:\\Windows\\System32\\netapi32.dll ");
but i get always the same error
The requirements section of the MSDN topic you linked to states that you must link the Netapi32.lib library. That is the step that you have missed and explains the missing external error.
As to how to resolve the problem it is hard to say for sure. You are not using the MS compiler and so the #pragma approach won't work. Consult the docs for your compiler/linker to work out how to link this library.
It looks like you are using a GCC based compiler and so need to add -lnetapi32 to the options.