MsiEnumProductsEx Not Working - c++

I have the following application, to check installed programs in a system:
#include <iostream>
#include <Msi.h>
#include <Windows.h>
using namespace std;
void main()
{
UINT ret;
DWORD dwIndex = 0;
DWORD dwContext = MSIINSTALLCONTEXT_ALL;
char szInstalledProductCode[39] = {0};
char szSid[128] = {0};
const char* szUserSid = "s-1-1-0";
DWORD cchSid;
MSIINSTALLCONTEXT dwInstalledContext;
do
{
memset(szInstalledProductCode, 0, sizeof(szInstalledProductCode));
cchSid = sizeof(szSid)/sizeof(szSid[0]);
ret = MsiEnumProductsEx(
NULL, // all the products in the context
szUserSid, // i.e.Everyone, all users in the system
dwContext,
dwIndex,
szInstalledProductCode,
&dwInstalledContext,
szSid,
&cchSid
);
if(ret == ERROR_SUCCESS)
{
char* name = MsiGetProductInfoEx (
szInstalledProductCode,
cchSid == 0 ? NULL : szSid,
dwInstalledContext,
INSTALLPROPERTY_INSTALLEDPRODUCTNAME
);
char* version = MsiGetProductInfoEx (
szInstalledProductCode,
cchSid == 0 ? NULL : szSid,
dwInstalledContext,
INSTALLPROPERTY_VERSIONSTRING
);
cout << name << endl;
cout << " - " << version << endl;
dwIndex++;
}
} while(ret == ERROR_SUCCESS);
}
I am using Microsoft Visual C++ Express 2010. The application is MBCS. In studio, these four things are in red (error):
MSIINSTALLCONTEXT_ALL
MSIINSTALLCONTEXT
MsiEnumProductsEx
MsiGetProductInfoEx
I linked the Msi.lib (Project properties -> Linker -> Input -> Additional Dependencies). I am just trying to figure out how MsiEnumProductsEx function works. I know there are other questions around, but I just can't understand why it isn't working because I think that I have everything for the functions to be available, at least. Thanks!

The MSIINSTALLCONTEXT_ALL (and related identifiers) are defined in <msi.h> only if _WIN32_MSI >= 300. You have to tell the Windows SDK what the minimum OS version you're targeting is, by defining a few macros before installing any SDK headers (like <msi.h> or <windows.h>).
You do that according to this MSDN page.
Once you've defined a suitable minimum version (looks like Windows XP SP2 and up), then _WIN32_MSI will be set to an appropriate level, and you should get the symbols.

Related

GetShortPathName fails with Chinese folder on a network drive

I want to get a short path name with the function GetShortPathName on a network drive, F:\, with a Chinese folder name. When I run the EXE file from that folder I don't see it is able to obtain the short path name. When I do that from the C:\ drive everything works fine.
Here is my code:
#include"stdafx.h"
#include<windows.h>
#include<tchar.h>
#include<stdio.h>
#include <iostream>
using namespace std;
#define BUFSIZE 4096
bool GetIsCaseCorrect(const WCHAR* fileName)
{
bool result = false;
// Correct case by converting to short path and back to long
WCHAR shortFileName[_MAX_PATH];
if (GetShortPathName(fileName, shortFileName, _MAX_PATH) != 0)
{
wchar_t correctFileName[_MAX_PATH];
wcout << "ShortFile " << shortFileName;
GetLongPathName(shortFileName, correctFileName, _MAX_PATH);
result = wcscmp(fileName, correctFileName) != 0;
}
return result;
}
int main() {
bool ret;
HMODULE hModule = GetModuleHandleW(NULL);
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);
ret = GetIsCaseCorrect(path);
getchar();
}
If I run this program the short path is not displayed on a non-system drive where folder is in Chinese.
My Windows OS is Windows 7.
As far as I know, the Windows 7 machine takes with the SMB 2.0 by default. GetShortPathNameW method is better supported with SMB 3.0.
You could follow this document below to enable SMB 3.0 with Win7.
https://support.microsoft.com/en-us/help/2696547/how-to-detect-enable-and-disable-smbv1-smbv2-and-smbv3-in-windows-and?wa=wsignin1.0%3Fwa%3Dwsignin1.0
Or you could follow this document below to check the volume state for Disable8dot3.
https://blogs.msdn.microsoft.com/winsdk/2013/10/09/getshortpathname-doesnt-return-short-path-name/
Best Regards,
Baron Bi

C++ RegGetValue function not returning correct Windows OS Version

I'm using the below code in a console application to get my Windows OS version:
#include <string>
#include <iostream>
#include <Windows.h>
int main()
{
DWORD dataSize = 0;
char buffer[256];
dataSize = sizeof(buffer);
RegGetValueA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"ProductName", RRF_RT_REG_SZ, 0, &buffer, &dataSize);
cout << buffer << endl;
return 0;
}
I have Windows 10 Pro installed, but the function is returning Windows 10 Enterprise. I have even manually navigated using regedit to the specified key and under "Product Name" I can see Windows 10 Pro. Here is an image of my regedit.
I ran another function RtlGetProductInfo(10, 0, 0, 0, f); and it returned the value of 0x48 for f, which according to Microsoft I have Windows 10 Enterprise Evaluation.
Now, at this point, I understand that something is messed up with my Windows installation, but why would my first code return another value than what is displayed for "ProductName" in my registry editor?
Edit: I should add that I've run the code on another Windows PC and it returns the correct version on that computer.

Incompatible with parameter of type "LPCWSTR"

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <dos.h>
using namespace std;
class Dir
{
public:
char* cat;
Dir()
{
cout << "(C:/*)\n";
cat = new char[50];
cin >> cat;
}
void virtual ShowFiles()
{
}
};
class Inside : public Dir
{
public:
void virtual ShowFiles()
{
HANDLE hSearch;
WIN32_FIND_DATA pFileData;
hSearch = FindFirstFile(cat, &pFileData);
if (hSearch != INVALID_HANDLE_VALUE)
do
{
// if ((pFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
cout << pFileData.cFileName << "\n";
} while (FindNextFile(hSearch, &pFileData));
FindClose(hSearch);
}
};
int main()
{
Dir *obj1[2];
obj1[1] = new Inside;
obj1[1]->ShowFiles();
return 0;
}
So I have a program, I need to show with dynamic char cat all file in directory, but it is compilable in Borland C++ but in Visual Studio 15 + Resharper it doesn't work. Severity Code Description Project File Line
Error (active) argument of type "char *" is incompatible with parameter of type "LPCWSTR"
To compile your code in Visual C++ you need to use Multi-Byte char WinAPI functions instead of Wide char ones.
Set Project -> Properties -> Advanced (or. General for older versions) -> Character Set option to Use Multi-Byte Character Set
also see the screenshot
I actually found another way to resolve this error since above method did not work for me.
I casted all my constant character strings with (LPCWSTR). The solution looks like this
Earlier
MessageBox(NULL,"Dialog creation failed! Aborting..", "Error", MB_OK);
After casting to LPCWSTR
MessageBox(NULL, (LPCWSTR) "Dialog creation failed! Aborting..", (LPCWSTR) "Error", MB_OK);
So just copying the (LPCWSTR) and pasting wherever this error was generated resolved all my errors.
Another way to come by this issue, is to use the Lmacro in front of your string.
MessageBox(NULL, L"Dialog creation failed! Aborting..", L"Error", MB_OK);
See: What does the 'L' in front a string mean in C++?
or
L prefix for strings in C++
you can use wchar_t
class Dir
{
public:
wchar_t* cat;
Dir()
{
wcout << "(C:/*)\n";
cat = new wchar_t[50];
wcin >> cat;
}
void virtual ShowFiles()
{
}
};
In Visual Studio 2013 and later, the MFC libraries for multi-byle character encoding (MBCS) will be provided as an add-on to Visual Studio
It will work for any settings:
#include <tchar.h>
MessageBox(NULL, _T("Dialog creation failed! Aborting.."), _T("Error"), MB_OK);

nVidia driver version from WMI is not what I want

I want to get driver version of nVidia video card.
So I used WMI and get data from "DriverVersion" obejct of "Win32_VideoController" class.
But it was like "9.18.13.1106"(file version) and what I wanted is something like "311.06"(treiber version).
Where can I get that information?
If it is impossible on WMI, I want to know other way to get that.
Thanks.
You can do this using NVML from nVidia's Tesla Deployment Kit. You can retrieve the internal driver version (the one you're accustomed to seeing for an nVidia driver) with code like this:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <nvml.h>
#include <windows.h>
namespace {
typedef nvmlReturn_t (*init)();
typedef nvmlReturn_t (*shutdown)();
typedef nvmlReturn_t (*get_version)(char *, unsigned);
class NVML {
init nvmlInit;
shutdown nvmlShutdown;
get_version nvmlGetDriverVersion;
std::string find_dll() {
std::string loc(getenv("ProgramW6432"));
loc += "\\Nvidia Corporation\\nvsmi\\nvml.dll";
return loc;
}
public:
NVML() {
HMODULE lib = LoadLibrary(find_dll().c_str());
nvmlInit = (init)GetProcAddress(lib, "nvmlInit");
nvmlShutdown = (shutdown)GetProcAddress(lib, "nvmlShutdown");
nvmlGetDriverVersion = (get_version)GetProcAddress(lib, "nvmlSystemGetDriverVersion");
if (NVML_SUCCESS != nvmlInit())
throw(std::runtime_error("Unable to initialize NVML"));
}
std::string get_ver() {
char buffer[81];
nvmlGetDriverVersion(buffer, sizeof(buffer));
return std::string(buffer);
}
~NVML() {
if (NVML_SUCCESS != nvmlShutdown())
throw(std::runtime_error("Unable to shut down NVML"));
}
};
}
int main() {
std::cout << "nVidia Driver version: " << NVML().get_ver();
}
Note that if you're writing this purely for your own use on a machine where you're free to edit the PATH, you can simplify this quite a bit. Most of the code deals with the fact that this uses NVML.DLL, which is in a directory that's not normally on the path, so the code loads that dynamically, and uses GetProcAddress to find the functions in it that we need to use. In this case, we're only using three functions, so it's not all that difficult to deal with, but it still at drastically increases the length of the code.
If we could ignore all that nonsense, the real code would just come out to something on this general order:
nvmlInit();
nvmlSystemGetDriverVersion(result, sizeof(result));
std::cout << result;
nvmlShutdown();
Anyway, to build it, you'll need a command line something like:
cl -Ic:\tdk\nvml\include nv_driver_version.cpp
...assuming you've installed the Tesla Deployment Kit at c:\tdk.
In any case, yes, I've tested this to at least some degree. On my desktop it prints out:
nVidia Driver version: 314.22
...which matches what I have installed.
To get the Nvidia driver version through C++ on Win64:
Download NVAPI https://developer.nvidia.com/rtx/path-tracing/nvapi/get-started, a few MB
The main folder of the downloaded archive contains several header files, one of which is nvapi.h. Those headers are needed for compilation. The subfolder amd64 contains nvapi64.lib, which is needed for linking. The following code will now show the driver version:
#include <iostream>
extern "C" {
#include "nvapi.h"
}
int main() {
NvAPI_Status status = NVAPI_OK;
NvAPI_ShortString str;
status = NvAPI_Initialize();
if (status == NVAPI_LIBRARY_NOT_FOUND) {
//in this case NvAPI_GetErrorMessage() will only return an empty string
std::printf("error no nvidia driver found\n");
} else if (status != NVAPI_OK) {
NvAPI_GetErrorMessage(status, str);
std::printf("error initializing nvapi: %s\n", str);
}
NvU32 version = 0;
NvAPI_ShortString branch;
status = NvAPI_SYS_GetDriverAndBranchVersion(&version, branch);
if (status != NVAPI_OK) {
NvAPI_GetErrorMessage(status, str);
std::printf("error getting driver version: %s\n", str);
} else {
std::printf("driver version %d.%d", version / 100, version % 100);
}
}

Make a VB-dll and load it in C++ application

I have a problem I've been struggeling with for a full week now, and I'm not able to solve it by myself. I've been googeling, and searching in all kind of forums... I have found lots of "this might work", tried it, but no, no success. If anyone have any clue, please, please, help me!
I'v got, from an external source, lots of classes and functions written in VB that I need to be able to use from a C++ application. My first though was: no problem, I turn the VB code into a dll, and load it from my C++-program. This was though harder than I ever could imagine. My C++-program is not written in Visual Studio, but for simplicity I started with trying to load my VB dll (written in Visual Studio 2010) from a Visual Studio C++ application. This is my code so far:
VB-code : DllModule : Class-library project
DllModule.vb
Namespace DllModule
Public Module DllModule
Public Const DLL_PROCESS_DETACH = 0
Public Const DLL_PROCESS_ATTACH = 1
Public Const DLL_THREAD_ATTACH = 2
Public Const DLL_THREAD_DETACH = 3
Public Function DllMain(ByVal hInst As Long, ByVal fdwReason As Long,
ByVal lpvReserved As Long) As Boolean
Select Case fdwReason
Case DLL_PROCESS_DETACH
' No per-process cleanup needed
Case DLL_PROCESS_ATTACH
DllMain = True
Case DLL_THREAD_ATTACH
' No per-thread initialization needed
Case DLL_THREAD_DETACH
' No per-thread cleanup needed
End Select
Return True
End Function
'Simple function
Public Function Add(ByVal first As Integer, ByVal sec As Integer) As Integer
Dim abc As Integer
abc = first + sec
Return abc
End Function
End Module
End Namespace
DllModule.def
NAME DllModule
LIBRARY DllModule
DESCRIPTION "My dll"
EXPORTS DllMain #1
Add #2
C++-code : TryVbDllLoad : Console application
TryVbDllLoad.cpp
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <strsafe.h>
extern "C" {
__declspec(dllimport) int __stdcall Add(int, int);
}
typedef int (__stdcall *ptf_test_func_1_type)(int, int);
int __cdecl _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE hdll = NULL;
hdll = LoadLibrary("DllModule.dll"); // load the dll
if(hdll) {
ptf_test_func_1_type p_func1=(ptf_test_func_1_type)GetProcAddress(hdll,"Add");
if(p_func1) {
int ret_val = (*p_func1)(1, 2);
} else {
DWORD dw = GetLastError();
}
FreeLibrary(hdll); // free the dll
} else {
DWORD dw = GetLastError();
}
return 0;
}
I can load the dll, but GetProcAddess returns NULL with error code 127 (the specified procedure could not be found).
I have tried to load the dll from a VB-application. This works (even without the .def-file). But I'm guessing there is no proper entry point created that the C++ application can use (when I open the dll in Dependency Walker I see no entry point or functions). I've tried compiling the VB-code both with and without "Register for COM interop".
1) What am I doing wrong?
2) If there isn't any nice way to solve this properly, what can I do instead of creating a dll? Is there any other way I can use the VB-classes and functions in my C++ application?
Kind Regards
Sara
Thanks for your answer Mare!
There must be some kind of error in my dll though, cause when I try to register is using regsvr32 I get: "The module C:/tmp/DllModule.dll was loaded, but the start address for DllRegisterServer was not found. Check that C:/tmp/DllModule.dll is a valid DLL- or OCX-file and try again."
Also, when I use
#import "C\tmp\DllModule.dll"
I get
fatal error C1083: Cannot open type library file: 'c:\tmp\dllmodule.dll'
I looked at the link with the tutorial, but there is a small problem: there are no such thing as "ActiveX DLL" to choose among all the project types. And yes, I do have Visual Studio 2010 Professional (a trial version, but still).
-- Sara
Thanks for all the input. I've come across another way to solve my problem, using a multifile assembly rather than my first dll approach.
I followed this HowTo-section: http://msdn.microsoft.com/en-us/library/226t7yxe.aspx#Y749
VB-code : DllModule : Class-library project
DllModule.vb
Imports System.Runtime.InteropServices
Namespace DllModuleNS
Public Class Class1
Public Function ClassAdd(ByRef first As Integer, ByRef sec As Integer) As Integer
Dim abc As Integer
abc = first + sec
Return abc
End Function
End Class
End Namespace
This file I compiled using both visual studio (to produce DllModule.dll-file) and cmd-line:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Vbc.exe /t:module DllModule.vb
(to produce DllModule.netmodule-file).
C++-code : TryVbDllLoad : Console application
TryVbDllLoad.cpp
#using <mscorlib.dll>
#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;
int _tmain(int argc, _TCHAR* argv[])
{
Class1^ me = gcnew Class1();
int a = 1, b = 2;
int xx = me->ClassAdd(a, b);
return 0;
}
In the TryVBDllLoad-project properties I changed:
Common Properties -> Framework and References : added DllModule-project as reference
Configuration Properties -> C/C++ -> General : /clr flag set
Configuration Properties -> Linker -> Input : Add Module To Assembly set to path to DllModule.netmodule (/ASSEMBLYMODULE:"DllModule.netmodule")
This resulted in that I could use the VB-class Class1 in VC++ code!
PROBLEM SOLVED!
I now took it one step further, and changed the TryVBDllLoad-project to a dll:
Configuration Properties -> General : Configurationtype Dynamic Library (.dll)
Configuration Properties -> Linker -> System : SubSystem Windows (/SUBSYSTEM:WINDOWS)
TryVbDllLoadClass.h
#ifndef TryVbDllLoadClass_H
#define TryVbDllLoadClass_H
class TryVbDllLoadClass
{
public:
TryVbDllLoadClass();
int Add(int a, int b);
};
#endif // TryVbDllLoadClass_H
TryVbDllLoadClass.cpp
#include "TryVbDllLoadClass.h"
#using <mscorlib.dll>
#using ".\..\ClassLibrary1\DllModule.netmodule"
using namespace DllModule::DllModuleNS;
TryVbDllLoadClass::TryVbDllLoadClass() {}
int TryVbDllLoadClass::Add(int a, int b)
{
Class1^ me = gcnew Class1();
int xx = me->ClassAdd(a, b);
return xx;
}
DllExport.h
#ifndef DLLEXPORT_H
#define DLLEXPORT_H
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#ifdef __dll__
#define IMPEXP __declspec(dllexport)
#else
#define IMPEXP __declspec(dllimport)
#endif // __dll__
extern "C" {
IMPEXP int __stdcall AddFunction(int);
}
#endif // DLLEXPORT_H
DllMain.h
#define __dll__
#include "dllExport.h"
#include " TryVbDllLoadClass.h"
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
return 1;
}
TryVbDllLoadClass * my;
IMPEXP int __stdcall AddFunction(int first, int second)
{
my = new TryVbDllLoadClass();
int res = my->Add(first, second);
delete my;
return res;
}
This dll I could then add to a non-visual-studio project just like a normal dll:
C++-code : LoadDll : Non-Visual-Studio-project (CodeBlocks in this case)
main.cpp
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "dllExport.h"
typedef int( * LPFNDLL_CREATE)(int, int);
HINSTANCE hDLL;
LPFNDLL_CREATE func;
using namespace std;
int main()
{
cout << "Hello world!" << endl;
int key = 35;
hDLL = LoadLibrary("TryVbDllLoadClass.dll");
if(hDLL)
{
cout << "Loaded: " << hDLL << endl;
func = (LPFNDLL_CREATE) (GetProcAddress(hDLL, "_AddFunction#4"));
if(func != NULL)
{
cout << "Connected: " << func << endl;
cout << "Function returns: " << func(key, key) << endl;
}
else cout << " ::: fail: " << GetLastError() << endl;
FreeLibrary(hDLL);
cout << "Freed" << endl;
}
else cout << " ::: fail: " << GetLastError() << endl;
printf("-> Goodbye world!\n");
return 0;
}
This way I can use the VB-classes given to me in my existing C++-project created outside Visuabl Studio. Finally...:)
With VB you do not get a "normal" DLL (at least this was the case in former times).
And you do not get Entry Points for functions.
But as i understood you, you have the VB source code and you can do with it whatever
is necessary. Here is a possible solution:
http://www.codeproject.com/Articles/21/Beginner-s-Tutorial-Calling-Visual-Basic-ActiveX-D
but try out first this less complicated way,
because i think a VB dll is always a COM dll, so you can:
register the dll using the Windows command
regsvr32 F:\proj\VBDllModule.dll
now your C++ code :
#import "F:\proj\VBDllModule.dll"
using namespace DllModule;
void CDialogTestDlg::OnButton1()
{
HRESULT hresult;
CLSID clsid;
_CTest *t; // a pointer to the CTest object
_bstr_t bstrA = L"hello";
_bstr_t bstrB = L" world";
_bstr_t bstrR;
::CoInitialize(NULL);
hresult=CLSIDFromProgID(OLESTR("VBTestLib.CTest"), &clsid);
hresult= CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
__uuidof(_CTest),(LPVOID*) &t);
if(hresult == S_OK)
{
bstrR = t->vbConcat(bstrA , bstrB);
AfxMessageBox((char*)bstrR);
}
}