I have a native process which uses .NET component via COM interop. Once the process is up, I am trying to get interface pointers to the various CLR managers such as ICLRDebugManager, ICLRGCManager, etc. using the ICLRControl interface pointer. I'm able to reach up to acquiring ICLRControl interface without a glitch. ICLRRuntimeInfo also correctly tells me that it is 4.0.x .net version when I call GetVersionString on it.
It is only that the ICLRControl::GetCLRManager keeps failing with error 0x80130122, which error code stands for HOST_E_INVALIDOPERATION. Searched the internet, but could not get information as to why this might be failing. Any help is much appreciated.
TIA.
WinCPP
Edit 1. Adding code snippet.
// ICLRRuntimeInfo interface pointer
CComQIPtr<ICLRRuntimeInfo> pCLRRuntimeInfo = pUnk;
if (!pCLRRuntimeInfo)
{
cout << "failed to get run time info interface pointer" << endl;
return;
}
TCHAR version[128];
memset(version, 0, 128);
DWORD count = 127;
pCLRRuntimeInfo->GetVersionString(version, &count);
cout << version << endl;
// ICLRRuntimeHost
CComPtr<ICLRRuntimeHost> pCLRRuntimeHost = 0;
hr = pCLRRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&pCLRRuntimeHost);
if (FAILED(hr))
{
cout << "failed to get run time host interface pointer" << endl;
return;
}
// ICLRControl
CComPtr<ICLRControl> pCLRControl = 0;
hr = pCLRRuntimeHost->GetCLRControl(&pCLRControl);
if (FAILED(hr))
{
cout << "failed to get clr control interface pointer" << endl;
return;
}
///////////////////////////////////////////
// Everything is successful upto this point
///////////////////////////////////////////
// ICLRGCManager
CComPtr<ICLRGCManager> pCLRGCManager = 0;
hr = pCLRControl->GetCLRManager(IID_ICLRGCManager, (LPVOID *)&pCLRGCManager);
if (FAILED(hr))
{
cout << "failed to get GC manager interface pointer" << endl;
return;
}
// Above call fails with the error 0x81031022, though everything is as per the MSDN documentation for the API
Looking at this source code on GitHub, it looks like CCorCLRControl::GetCLRManager will return HOST_E_INVALIDOPERATION if the runtime has already been started.
This explains why you are receiving that error code when attempting to "latch on to already loaded CLR instance," but that you meet with success when you create a CLR instance explicitly.
Related
I'm currently writing a simple application to retrieve a list of the PnP devices of my computer. To do this, I'm making use of the Windows PortableDeviceApi Library.
So far I have the following code:
#include <iostream>
#include <PortableDeviceApi.h>
#include <wrl.h>
inline void getDeviceHWIDs() {
// Initialize
CoInitialize(nullptr);
// create portable device manager object
Microsoft::WRL::ComPtr<IPortableDeviceManager> device_manager;
HRESULT hr = CoCreateInstance(CLSID_PortableDeviceManager,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&device_manager));
if (FAILED(hr)) {
std::cout << "! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = " << std::hex << hr << std::endl;
}
// obtain amount of devices
DWORD pnp_device_id_count = 0;
if (SUCCEEDED(hr)) {
hr = device_manager->GetDevices(nullptr, &pnp_device_id_count);
if (FAILED(hr)) {
std::cout << "! Failed to get number of devices on the system, hr = " << std::hex << hr << std::endl;
}
}
std::cout << "Devices found: " << pnp_device_id_count << std::endl;
// Uninitialize
CoUninitialize();
}
The code compiles and runs successfully, however pnp_device_id_count is returning 0, indicating that there are no PnP devices connected to my computer. This is obviously an incorrect result, since Get-PnpDevice in PowerShell returns a large list of devices.
Any help would be much appreciated, as I'm a bit stumped over this ':(
Thank you :)
This is expected, Windows Portable Devices provides only a way to communicate with music players, storage devices, mobile phones, cameras, and many other types of connected devices.
It will not enumerate all devices on your system. Connect an IPhone and you will see pnp_device_id_count become 1.
To enumerate all devices you can use WinRT's Windows.Devices.Enumeration Namespace or the ancient Setup API.
Here is a (C# but you can do the same with C++) sample for using WinRT's one https://github.com/smourier/DeviceExplorer and a C++ sample for using Setup API: https://www.codeproject.com/Articles/14412/Enumerating-windows-device
This question is about the usage of URLDownloadToFile API.
I am using URLDownloadToFile in Visual C++ MFC application. On Windows server 2008, the program is working fine.
Sample code:
// invalidate cache, so file is always downloaded from web site
// (if not called, the file will be retrieved from the cache if
// it's already been downloaded.)
DeleteUrlCacheEntry(aCSVDownloadURL);
CallbackHandler callbackHandler;
IBindStatusCallback* pBindStatusCallback = NULL;
callbackHandler.QueryInterface(IID_IBindStatusCallback,
reinterpret_cast<void**>(&pBindStatusCallback));
HRESULT hr = URLDownloadToFile(
NULL, // A pointer to the controlling IUnknown interface
DownloadURL,
FileName, // Filename to save the downloaded file in local
0, // Reserved. Must be set to 0.
pBindStatusCallback // Callback interface to catch the download response; basically the file name
);
if (hr == S_OK)
{
cout << "Download OK" << endl;
}
else if (hr == E_OUTOFMEMORY)
{
cout << "The buffer length is invalid, or there is insufficient memory to complete the operation." << endl;
} else if (hr == INET_E_DOWNLOAD_FAILURE)
{
cout << "The specified resource or callback interface was invalid." << endl;
}
else {
cout << "Other error" << endl;
}
But when run the app in Windows Server 2012 R2, I get the below error:
Error code: INET_E_DOWNLOAD_FAILURE
Description: The specified resource or callback interface was invalid.
Have done googling for few hours, but still no luck. It would be very much appreciated if there is a solution.
The program is created using Visual Studio 2015
#include <Windows.h>
#include <iostream>
#include <vector>
#include <string>
//
// Desired Output: Text in clipboard should be displayed to the screen.
//
int main( void )
{
//
// OLE COM Interface
//
HRESULT hr;
// Get Clipeboard
IDataObject* pcb = 0;
OleGetClipboard(&pcb);
// Get Clipeboard Data Interface
FORMATETC format;
format.cfFormat = CF_TEXT;
format.ptd = NULL;
format.dwAspect = DVASPECT_CONTENT;
format.lindex = -1;
format.tymed = TYMED_ISTREAM;
STGMEDIUM medium;
hr = pcb->GetData(&format, &medium);
if( FAILED(hr) )
return hr;
// Get Stat of returned IStream
IStream* pis = medium.pstm;
STATSTG stat;
ULONG cb = 0;
hr = pis->Stat(&stat,STATFLAG_DEFAULT);
if( SUCCEEDED(hr) )
{
if( stat.pwcsName )
std::wcout << L"Name: " << stat.pwcsName << std::endl;
std::cout << "DataSize: " << stat.cbSize.QuadPart << std::endl;
std::cout << "Type: " << stat.type << std::endl;
cb = stat.cbSize.QuadPart;
}
// Read Data from IStream
std::vector<char> v;
v.resize(cb);
ULONG ret;
hr = pis->Read(v.data(), cb, &ret);
if( FAILED( hr ) )
{
std::cout << "Failed to Read" << std::endl;
}
else
{
std::string out(v.begin(),v.end());
std::cout << "Read " << ret << "chars. Content: {" << out << "}" << std::endl;
}
pis->Release();
//
// My Output when I have 40 characters in Clipboard
//
// DataSize: 40
// Type: 2
// Read 0chars. Content: { }
// The number of characters are correct, but content always appear empty.
}
Hello.
I'm trying to gain access to clipboard through IStream interface.
IStream::Stat seems like giving me correct status of the IStream, but IStream::Read is not really giving me any data.
I have almost zero experience in using COM object and IStream interface.
Please, point out if there is obvious error.
Thank you.
My condolences for having to use COM and C++. It's been 4 or 5 years since I've touched the stuff, but looking at what you have, I'd guess one of two things is a problem:
The IStream pointer starts out at the end of the data. In this case you have to call pis->Seek(0, STREAM_SEEK_SET, NULL) to reset it at the beginning. It may be that the call to pis->Read() returns S_FALSE rather than S_OK; the MSDN docs on Read() say that this can occur if the stream pointer is at the end of the stream.
The Clipboard just doesn't support using IStream. Actually I've never heard of doing this; I thought the usual method was to access Clipboard data as a global memory block. (See this example which is a lot simpler than your code) IStreams are necessary when you get into icky subjects like structured storage which was the old way that MS Office applications stored hierarchical data in one file.
A side note: if you don't have to use C++, and are familiar with other languages that have bindings for Windows clipboard access (C#, VB for "native" .NET access; Java has portable Clipboard access with a subset of the native Windows features, I think Python does also), you don't have to mess with any of those ugly COM features.
I'm probably just blind, but I cannot see any errors here (and I am looking on this issue already for days now...)
I am trying to get the Patch Priority (Severity) from the Windows Update Interface using the following piece of code in Visual Studio:
#include "stdafx.h"
#include <wuapi.h>
#include <iostream>
#include <ATLComTime.h>
#include <wuerror.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
hr = CoInitialize(NULL);
IUpdateSession* iUpdate;
IUpdateSearcher* searcher;
ISearchResult* results;
BSTR criteria = SysAllocString(L"IsInstalled=0");
hr = CoCreateInstance(CLSID_UpdateSession, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&iUpdate);
hr = iUpdate->CreateUpdateSearcher(&searcher);
wcout << L"Searching for updates ..."<<endl;
hr = searcher->Search(criteria, &results);
SysFreeString(criteria);
switch(hr)
{
case S_OK:
wcout<<L"List of applicable items on the machine:"<<endl;
break;
case WU_E_LEGACYSERVER:
wcout<<L"No server selection enabled"<<endl;
return 0;
case WU_E_INVALID_CRITERIA:
wcout<<L"Invalid search criteria"<<endl;
return 0;
}
IUpdateCollection *updateList;
IUpdateCollection *bundledUpdates;
IUpdate *updateItem;
IUpdate *bundledUpdateItem;
LONG updateSize;
LONG bundledUpdateSize;
BSTR updateName;
BSTR severity;
results->get_Updates(&updateList);
updateList->get_Count(&updateSize);
if (updateSize == 0)
{
wcout << L"No updates found"<<endl;
}
for (LONG i = 0; i < updateSize; i++)
{
updateList->get_Item(i,&updateItem);
updateItem->get_Title(&updateName);
severity = NULL;
updateItem->get_MsrcSeverity(&severity);
if (severity != NULL)
{
wcout << L"update severity: " << severity << endl;
}
wcout<<i+1<<" - " << updateName << endl;
// bundled updates
updateItem->get_BundledUpdates(&bundledUpdates);
bundledUpdates->get_Count(&bundledUpdateSize);
if (bundledUpdateSize != 0)
{
// iterate through bundled updates
for (LONG ii = 0; ii < bundledUpdateSize; ii++)
{
bundledUpdates->get_Item(ii, &bundledUpdateItem);
severity = NULL;
bundledUpdateItem->get_MsrcSeverity(&severity);
if (severity != NULL)
{
wcout << L" bundled update severity: " << severity << endl;
}
}
}
}
::CoUninitialize();
wcin.get();
return 0;
}
So here's the issue: updateItem->get_MsrcSeverity(&severity); is not returning anything. If I catch the result code with an HRESULT it always returns S_OK.
Link to MSDN IUpdate MsrcSeverity: http://msdn.microsoft.com/en-us/library/windows/desktop/aa386906(v=vs.85).aspx
Can you see what I am doing obviously wrong or is the get_MsrcSeverity function currently broken?
#EDIT: Changed the code to iterate through "BundledUpdates" as suggested.
#EDIT2: the code now outputs the severity value of the updateItem as well as the bundledUpdatesItem, but it's always NULL.
I also know there is one important update waiting for my computer - regarding to Windows Update in the control panel. It is KB2858725.
#EDIT3: Okay, it turns out, KB2858725 is no security update and therefore has no severity rating by Microsoft. But how does Microsoft Windows Update now categorize the updates in "important" and "optional" like you can see it in control panel's update?
Thank you for any hints!
// Markus
I've been struggling with the exact same problem for hours now... I finally figured out that Microsoft only seems to set the MsrcSeverity value on some updates. For general Windows updates, it's usually null. For most security updates it's set to one of:
"Critical"
"Moderate"
"Important"
"Low"
It seems as though the "Unspecified" value is never used, though it is documented in MSDN (http://msdn.microsoft.com/en-us/library/microsoft.updateservices.administration.msrcseverity(v=vs.85).aspx).
I wrote a small C# program to list all available updates and their reported severity. It requires a reference to WUApiLib:
using System;
using WUApiLib;
namespace EnumerateUpdates
{
class Program
{
static void Main(string[] args)
{
var session = new UpdateSession();
var searcher = session.CreateUpdateSearcher();
searcher.Online = false;
// Find all updates that have not yet been installed
var result = searcher.Search("IsInstalled=0 And IsHidden=0");
foreach (dynamic update in result.Updates)
{
Console.WriteLine(update.Title + ": " + update.Description);
Console.WriteLine("Severity is " + update.MsrcSeverity);
Console.WriteLine();
}
Console.ReadLine();
}
}
}
Hope this helps someone!
Look for bundled updates in the list. The bundled updates does not have some properties or methods as described on this page.
Remarks
If the BundledUpdates property contains an IUpdateCollection, some
properties and methods of the update may only be available on the
bundled updates, for example, DownloadContents or CopyFromCache.
The update you are processing in is a bundled update. Extract the individual updates from this bundle, it will have the property you are looking out for.
The IUpdate interface has a method get_BundledUpdates which gets you a IUpdateCollection if the size of this collection is greater then 0, this is a bundled update.
I'm trying to read the status and some other information from a printer, however I'm not getting any data returned from the printer. I can't figure out what I'm missing or doing wrong?
I'm using Qt creator where I have included the WinSpool library
As a side note: This is my first time trying to read data from a piece of hardware.
The msdn pages for the printer functions are:
SetPrinterData GetPrinterData OpenPrinter
Code
BOOL status = false;
HANDLE hPrinter = NULL;
PRINTER_DEFAULTS defaults;
defaults.pDatatype = (LPTSTR)__TEXT("RAW");
defaults.pDevMode = 0;
defaults.DesiredAccess = PRINTER_READ;
status = OpenPrinter((LPTSTR)__TEXT("CN551A"),&hPrinter,&defaults);
if(status) {
qDebug() << "Status: OPEN OK";
}
// pValueName found in registry
LPTSTR pValueName = (LPTSTR)"PrinterData";
DWORD type = REG_BINARY;
BYTE pData[2];
pData[0] = 0;
pData[1] = 0;
status = SetPrinterData(&hPrinter,pValueName,type,pData,sizeof(pData));
if(status) {
qDebug() << "Status: SET OK";
}
BYTE buffer[263];
LPDWORD pcbNeeded = 0;
LPDWORD pType = (LPDWORD)REG_BINARY;
status = GetPrinterData(&hPrinter, pValueName,pType,buffer,sizeof(buffer),
pcbNeeded);
if(status) {
qDebug() << "Status: GET OK";
qDebug() << "pType: " << pType;
qDebug() << "pcbNeeded " << pcbNeeded;
qDebug() << "buffer " << *buffer;
/* Prints a bunch of numbers
for(int i =0; i < sizeof(buffer); i++) {
qDebug() << buffer[i];
}
*/
}
ClosePrinter(&hPrinter);
Output
Status: OPEN OK
Status: SET OK
Status: GET OK
pType: 0x3
pcbNeeded 0x0
buffer 1
I'm using Qt creator where I have included the WinSpool library
As a side note: This is my first time trying to acheive this.
Edit
I found a C# program which reads status and information in the ReadBytesFromPrinter function in PrintLabel.cs using Windows API calls, just like I would like to, but I still wasn't able to figure out my mistake/error. Thought I'd link it, if someone could spot what's wrong with my code compared to theirs.
You're misinterpreting the return values of the GetPrinterData and SetPrinterData. Those calls are in fact failing, not succeeding. The return value for success is ERROR_SUCCESS, which I believe you'll find is zero. Any other value is the error code you need to display and investigate. See the MSDN entry for SetPrinterData.