Please take a look at my code:
#include <windows.h>
#include <Sti.h>
#include <iostream>
#pragma comment (lib, "Sti.Lib")
using namespace std;
void main ()
{
HRESULT hr = CoInitialize(NULL);
PSTI iface = 0;
hr = StiCreateInstance(GetModuleHandle(NULL), STI_VERSION, &iface, NULL);
DWORD numDevices = 0;
STI_DEVICE_INFORMATION* devices = NULL;
hr = iface->GetDeviceList(NULL, NULL, &numDevices, (void**) &devices);
cout << hr;
hr = iface->Release();
cin.get();
}
GetDeviceList gives me "There was no match for the specified key in the index." Any idea as to what it means? Google doesn't seem to help here.
Everything else is OK (initialization, I mean).
Thanks in advance.
Update: It works on Win XP virtual machine, but still fails on host Win 7 x64. Odd.
STI only works on Win XP, that's all.
Related
I'm trying the following code:
hr = ddr7->QueryInterface(IID_IDirect3D7,(void**)&d3d7)
the hr returned is E_NOINTERFACE, how does this happen?
On my Windows 10 system Version 1909 (18363) [x64], this worked fine:
#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <ddraw.h>
#include <d3d.h>
typedef HRESULT ( WINAPI* LPDIRECTDRAWCREATEEX )( GUID FAR * lpGuid, LPVOID *lplpDD, REFIID iid,IUnknown FAR *pUnkOuter );
void main()
{
HINSTANCE hInstDDraw = nullptr;
LPDIRECTDRAW pDDraw = nullptr;
hInstDDraw = LoadLibraryW( L"ddraw.dll" );
if( hInstDDraw )
{
auto pDDCreate = reinterpret_cast<LPDIRECTDRAWCREATEEX>(GetProcAddress( hInstDDraw, "DirectDrawCreateEx" ) );
if (pDDCreate)
{
HRESULT hr = pDDCreate(nullptr, reinterpret_cast<LPVOID*>(&pDDraw), IID_IDirectDraw7, nullptr);
if (SUCCEEDED(hr))
{
LPDIRECT3D7 d3d7 = nullptr;
hr = pDDraw->QueryInterface(IID_IDirect3D7, reinterpret_cast<LPVOID*>(&d3d7));
if (SUCCEEDED(hr))
{
printf("Worked\n");
return;
}
else
{
printf("QI Failed: %08X\n", static_cast<int>(hr));
}
}
else
{
printf("DDCreate Failed: %08X\n", static_cast<int>(hr));
}
}
FreeLibrary( hInstDDraw );
}
printf("Failed\n");
}
You should make sure the HRESULT from your call to DirectDrawCreateEx worked. Also, it's possible it could be an issue with your drivers or setup.
Your original question really should include more code, particularly the DirectDrawCreateEx since the QueryInterface alone isn't particularly informative.
Happens to me too, works fine on 32bit application but fails on 64bit application. I'm on Windows 10 x64 version 10.0.18363.1082. As others already commented, D3D7 is already obsolete.
The updates involved are: KB4532938 and KB4528760
This is the code:
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
HMODULE hInst;
HANDLE hImg = NULL;
hInst = LoadLibrary(L"C:\\Users\\asd\\Desktop\\asd\\test.exe");
hImg = LoadImageW(hInst, MAKEINTRESOURCEW(5234), 2, 0, 0, 0);
if (!hImg)
cout << GetLastError() << endl;
cout << hImg;
}
This is the .exe containing the cursor (it's a blank ahk script)
Before the updates:
Output: NOT-null handle and error-code 1813
It works!
After the updates:
Output: NULL handle and error-code 1813
It doesn't work!
The only difference is the installed updates.
The questions are:
Is it a bug?
How is it possible that the resource exists, the name is correct, the format is correct and it fails?
What changed that made it break, was it a bug that made it work in the first place?
How can I report this to Microsoft?
Since it is not easy to clear in comments, I post it as an answer.
I did tests to reproduce this problem and found that it was only related to "KB4528760 update"(you don't need uninstall both of them).
I use EnumResourceTypes, EnumResourceNames to get that the resource does exist:
name = MAKEINTRESOURCE(5234), type = RT_ANICURSOR.
Use FindResource and specify the resource type to RT_ANICURSOR did work.
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
HMODULE hInst;
HANDLE hImg = NULL;
hInst = LoadLibrary(L"C:\\Users\\asd\\Desktop\\asd\\test.exe");
HRSRC hResInfo = FindResource(hInst, MAKEINTRESOURCE(5234), RT_ANICURSOR);
hImg = LoadResource(hInst, hResInfo);
if (!hImg)
cout << GetLastError() << endl;
cout << hImg;
}
According to this MSDN doc, we may pass NULL for the path argument:
path [in]
The name of the task. If this value is NULL, the task will be registered in the root task folder and the task name will be a GUID value created by the Task Scheduler service.
I have a code that use this behavior. The code works fine in Win7 and 8.1, but not in my Win10 box (ver 1709 64-bit, build 16299). In Win10, it will return 0x80070005 aka "Access Denied" when path is NULL. If I specify a name like "Foobar", it will work fine.
Test code:
// Link comsuppw.lib and taskschd.lib.
#include <stdio.h>
#include <windows.h>
#include <atlbase.h>
#include <atlstr.h>
#include <shlobj.h>
#include <taskschd.h>
#include <comutil.h>
class AutoHR {
HRESULT hr;
public:
void operator=(HRESULT hr)
{
this->hr = hr;
if (FAILED(hr)) {throw *this;}
}
HRESULT GetHR() const { return hr; }
};
static void TestTaskSched()
{
AutoHR hr;
CComPtr<ITaskService> taskSvc;
CComPtr<ITaskFolder> taskFol;
CComPtr<ITaskDefinition> taskDef;
CComPtr<IActionCollection> taskAC;
CComPtr<IAction> taskAction;
CComPtr<IExecAction> taskEA;
CComPtr<IRegisteredTask> registeredTask;
try {
hr = taskSvc.CoCreateInstance(CLSID_TaskScheduler, nullptr, CLSCTX_ALL);
hr = taskSvc->Connect(CComVariant(),CComVariant(),CComVariant(),CComVariant());
hr = taskSvc->GetFolder(_bstr_t(L""), &taskFol);
hr = taskSvc->NewTask(0, &taskDef);
hr = taskDef->get_Actions(&taskAC);
hr = taskAC->Create(TASK_ACTION_EXEC, &taskAction);
hr = taskAction.QueryInterface<IExecAction>(&taskEA);
hr = taskEA->put_Path(_bstr_t(L"C:\\Windows\\System32\\cmd.exe"));
hr = taskEA->put_Arguments(_bstr_t(L"/k echo Testing"));
// Note that NULL is passed as the first argument.
hr = taskFol->RegisterTaskDefinition(nullptr, taskDef,
TASK_CREATE_OR_UPDATE, CComVariant(), CComVariant(),
TASK_LOGON_NONE, CComVariant(), ®isteredTask);
MessageBoxW(nullptr, L"Succeeded!", L"OK", MB_ICONINFORMATION);
}
catch (AutoHR const &autohr) {
WCHAR buf[99] = {0};
wsprintfW(buf, L"HRESULT error 0x%.8X\n", autohr.GetHR());
MessageBoxW(nullptr, buf, nullptr, MB_ICONERROR);
}
}
int main()
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
TestTaskSched();
CoUninitialize();
}
return 0;
}
Test result:
Questions:
1) Is there a behavior change between Win10 and older Windows? I suspect there is, but I cannot find any doc that mentions it.
2) Any good alternative for this behavior? I hope I don't have to generate GUID by myself for temporary task creation.
I have an installer that tries to (re)start my application in the current user context after the installation is done.
The installer runs in the SYSTEM context and before launching the application it attempts (and theoretically succeeds) to impersonate the current user. However, when I look in the task manager, I see that my application is running in the SYSTEM context.
This is (a snippet from) my code:
TCHAR szUsername[128] = _T("");
DWORD dwUsernameSize = 128;
GetUserName(szUsername, &dwUsernameSize);
// Lets the calling process impersonate the security context of a logged-on user.
if (!ImpersonateLoggedOnUser(hToken))
{
throw Win32Exception(GetLastError(), _T("Failed to impersonate current user"));
}
TCHAR szUsername2[128] = _T("");
DWORD dwUsernameSize2 = 128;
GetUserName(szUsername2, &dwUsernameSize2);
MLOGD(_T("ProcessUtils::StartProcessInCurrentUserContext: Successfully impersonated %s"), szUsername2);
ProcessUtils::StartProcess(sExeName, lstParams, sWorkingDir, bWaitToFinish, errCode);
ProcessUtils::StartProcess is a wrapper around CreateProcess.
szUsername contains SYSTEM and szUsername2 contains the current user. So ImpersonateLoggedOnUser is successful.
However, as mentioned above, the process is started in the SYSTEM context, not the current user one.
I'm not sure how helpful this might be, but my installer is written in NSIS and it's calling the function that contains the code from above via a plugin written in C/C++.
Does anyone know why my application doesn't start in the current user context?
Win32 CreateProcess creates a process in the same security context as the caller which is SYSTEM (even though you are impersonating).
Think you need to be calling CreateProcessAsUser.
I had a very similar problem a couple of years ago when I was also
working on an installer application. After A LOT of frustration, caused
by failed attempts to start an application in the context of the current
user using CreateProcessAsUser, I've finally given up. After a thorough
search on the web, I've found a briliant implementation that uses
IShellDispatch2 interface. Here is an example:
#include <Windows.h>
#include <exdisp.h>
#include <Shobjidl.h>
#include <Shlwapi.h>
#include <comutil.h>
#include <SHLGUID.h>
#include <cstdlib>
#include <iostream>
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "comsuppw.lib")
bool ShellExecuteAsCurrentUser(const TCHAR *pcOperation, const TCHAR *pcFileName, const TCHAR *pcParameters,
const TCHAR *pcsDirectory, const DWORD dwShow)
{
bool bSuccess = false;
IShellWindows *psw = NULL;
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
if(SUCCEEDED(hr))
{
HWND hwnd = 0;
IDispatch* pdisp = NULL;
_variant_t vEmpty;
if(S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, reinterpret_cast<long*>(&hwnd), SWFO_NEEDDISPATCH, &pdisp))
{
if((hwnd != NULL) && (hwnd != INVALID_HANDLE_VALUE))
{
IShellBrowser *psb;
hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
if(SUCCEEDED(hr))
{
IShellView *psv = NULL;
hr = psb->QueryActiveShellView(&psv);
if(SUCCEEDED(hr))
{
IDispatch *pdispBackground = NULL;
HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
if(SUCCEEDED(hr))
{
IShellFolderViewDual *psfvd = NULL;
hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
if(SUCCEEDED(hr))
{
IDispatch *pdisp = NULL;
hr = psfvd->get_Application(&pdisp);
if(SUCCEEDED(hr))
{
IShellDispatch2 *psd;
hr = pdisp->QueryInterface(IID_PPV_ARGS(&psd));
if(SUCCEEDED(hr))
{
_variant_t verb(pcOperation);
_variant_t file(pcFileName);
_variant_t para(pcParameters);
_variant_t dir(pcsDirectory);
_variant_t show(dwShow);
if(SUCCEEDED(psd->ShellExecute(file.bstrVal, para, vEmpty, verb, show)))
bSuccess = true;
psd->Release();
psd = NULL;
}
pdisp->Release();
pdisp = NULL;
}
}
pdispBackground->Release();
pdispBackground = NULL;
}
psv->Release();
psv = NULL;
}
psb->Release();
psb = NULL;
}
}
pdisp->Release();
pdisp = NULL;
}
psw->Release();
psw = NULL;
}
return bSuccess;
}
int main(int argc, char *argv[])
{
CoInitialize(NULL);
if(ShellExecuteAsCurrentUser(L"open", L"notepad", nullptr, nullptr, SW_SHOWNORMAL))
std::cout << "SUCCESS" << std::endl;
CoUninitialize();
return 0;
}
This is just a quick demo, the implementation of ShellExecuteAsCurrentUser can be
improved by using smart pointers for COM interfaces and some refactoring. This method
worked for me on versions WinXP SP3 - Win 8.1, not sure if it works on Windows 10. For
more details, check the authors github page:
https://github.com/lordmulder/stdutils/tree/master/Contrib/StdUtils
If you had read the documentation for CreateProcess, you would have found the answer to your question in the first three sentences:
Creates a new process and its primary thread. The new process runs in the security context of the calling process.
If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation token.
There really isn't much else to say; the behaviour you describe is as documented. If you want to create a process as another user, you must use CreateProcessAsUser or one of the related functions.
I'm developing a sample code to get information about the Windows Updates Monitoring.
I bumped into Windows Update Agent APIs. link: http://msdn.microsoft.com/en-us/library/windows/desktop/aa387099(v=vs.85).aspx
But I'm not able to find any APIs for win32. I find only C#/.NET Interfaces.
Are there any corresponding win32 APIs?
Specifically I want to find out the "release date" of a windows update/patch.
Look forward to any suggestions and guidance.
Srivathsa
The WUA API includes a set of COM interfaces which can be used from C++ Apps, so try these IUpdateSearcher, IUpdateSession and IUpdate.
Check this sample c++ application which retrieve the updates and the date of release.
#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=1 or IsHidden=1 or IsPresent=1");
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;
IUpdate *updateItem;
LONG updateSize;
BSTR updateName;
DATE retdate;
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);
updateItem->get_LastDeploymentChangeTime(&retdate);
COleDateTime odt;
odt.m_dt=retdate;
wcout<<i+1<<" - "<<updateName<<" Release Date "<< (LPCTSTR)odt.Format(_T("%A, %B %d, %Y"))<<endl;
}
::CoUninitialize();
wcin.get();
return 0;
}