TCHAR Temp[MAX_PATH] = { 0, };
HRESULT hr = NULL;
PIDLIST_ABSOLUTE pidl; //=LPITEMIDLIST
IShellItem2 *_psiDrop=NULL;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); //must add this!
SHParseDisplayName(L"C:\\", NULL, &pidl, 0, NULL);
if (SHGetPathFromIDList(pidl, Temp))
{
wprintf(L"%s\n", Temp);
}
hr = SHCreateItemFromIDList(pidl, IID_PPV_ARGS(&_psiDrop));
if (FAILED(hr))
{
wprintf(L"SHCreateItemFromIDList failed");
}
how can i initialize IShellItem2 to use PIDLIST_ABSOLUTE ?
_psiDrop has been NULL.
Related
I have a client application written in C++, and a server written in Python. This application has several functions, including getting a screenshot of the client's desktop and getting this file on the server.
When I run these programs without any add-ons, everything works. I need to upload my client to the service, and I do it through CreateProcess[client file] inside of my service. All other functions besides the screenshot work with this approach.
Server code, getting a screenshot:
if (cState == State.GETTING_SCREENSHOT):
message = "SCREENSHOT".encode('utf-8')
MySend(client_sock , message)
curr_number = 0
with open("settings.txt" , 'r') as settings:
curr_number_str = settings.readline()
curr_number = int(curr_number_str)
with open("settings.txt" , 'w') as settings:
settings.write(str(curr_number + 1))
screenshot_file = str(curr_number) + ".png"
with open(screenshot_file , 'wb') as file:
while True:
data = MyRecv(client_sock , 40000)
data_arr = bytearray(data)
if (data_arr[:10] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'):
continue
if (b'ENDOFF' in data):
break
file.write(data)
cState = State.INPUT_COMMAND
Client code:
case SENDING_SCREENSHOT_IN_PROGRESS:
{
wchar_t PathToLocalAppDataFolder[MAX_PATH];
if (FAILED(SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, PathToLocalAppDataFolder))) {
LoadMessage("Error in ShGetFolderPathW");
break;
}
std::wstring PathToScreenshot = std::wstring(PathToLocalAppDataFolder) + L"\\1.png";
if (!SaveScreen(PathToScreenshot.c_str())) {
LoadMessage("SaveScreen api-func failed");
break;
}
HANDLE hFile = CreateFile(PathToScreenshot.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
LoadMessage("Can not open screenshot file");
break;
}
DWORD dwRead = 1;
BYTE buffSend[BIG_BUFFLEN];
while (dwRead) {
ZeroMemory(buffSend, BIG_BUFFLEN);
dwRead = 0;
ReadFile(hFile, buffSend, BIG_BUFFLEN, &dwRead, NULL);
MySend(ClientSoc, (char*)buffSend, dwRead, 0);
}
CloseHandle(hFile);
char message[SMALL_BUFFLEN] = "ENDOFFILE";
MySend(ClientSoc, message, BIG_BUFFLEN, 0);
DeleteFile(PathToScreenshot.c_str());
cState = WAITING_FOR_INCOMING_COMMAND;
break;
}
Service code:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <shlobj_core.h>
#include <string>
#include "api.h"
#include <fstream>
#pragma comment(lib , "API.lib")
#pragma warning(disable:4996)
wchar_t SERVICE_NAME[] = L"RemoteController";
bool isCreate = FALSE;
SERVICE_STATUS ServiceStatus = { 0 };
SERVICE_STATUS_HANDLE hServiceStatus; //StatusHandle
HANDLE ServiceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv);
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode);
DWORD WINAPI ServiceWorkerThreadEntry(LPVOID lpParam);
VOID Install(VOID);
BOOL dirExists(const wchar_t* dir_path);
int main(int argc, char* argv[]) {
FreeConsole();
Install();
SERVICE_TABLE_ENTRY ServiceTable[] = {
{SERVICE_NAME , (LPSERVICE_MAIN_FUNCTION)ServiceMain} ,
{NULL , NULL}
};
if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) {
LoadMessage("Service.exe : StartServiceCtrlDIspathcer error");
return GetLastError();
}
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) {
DWORD Status = E_FAIL;
hServiceStatus = RegisterServiceCtrlHandler(
SERVICE_NAME,
ServiceCtrlHandler
);
if (hServiceStatus == NULL) {
LoadMessage("Service.exe : RegisterServiceCtrlHandler failed");
return;
}
ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
ServiceStopEvent = CreateEventW(NULL, TRUE, FALSE, L"RemoteControllerEvent");
if (ServiceStopEvent == NULL) {
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = GetLastError();
ServiceStatus.dwCheckPoint = 1;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
return;
}
}
//start
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThreadEntry, NULL, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(ServiceStopEvent);
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 3;
if (!SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode) {
switch (CtrlCode) {
case SERVICE_CONTROL_STOP:
if (ServiceStatus.dwCurrentState != SERVICE_RUNNING) break;
ServiceStatus.dwControlsAccepted = 0;
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 4;
if (SetServiceStatus(hServiceStatus, &ServiceStatus) == FALSE) {
LoadMessage("Service.exe : SetServiceStatus failed");
return;
}
SetEvent(ServiceStopEvent);
default:
break;
}
}
BOOL dirExists(const wchar_t* dir_path) {
DWORD dwAttributes = GetFileAttributes(dir_path);
if (dwAttributes == INVALID_FILE_ATTRIBUTES) return FALSE;
if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) return TRUE;
return FALSE;
}
VOID Install(VOID) {
SC_HANDLE schSCManager;
SC_HANDLE schService;
wchar_t curr_path[MAX_PATH];
if (!GetModuleFileName(NULL, curr_path, MAX_PATH)) {
LoadMessage("Service.exe : GetModuleFilename failed");
return;
}
schSCManager = OpenSCManager(
NULL, NULL, SC_MANAGER_ALL_ACCESS
);
if (schSCManager == NULL) {
LoadMessage("Service.exe : OpenSCManager failed[with SC_MANAGER_ALL_ACCESS]");
return;
}
schService = CreateService(
schSCManager, SERVICE_NAME, SERVICE_NAME, SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
curr_path, NULL, NULL, NULL, NULL, NULL);
if (schService == NULL) {
LoadMessage("Service.exe : CreateService failed");
CloseServiceHandle(schSCManager);
return;
}
if (StartService(schService , 0 , NULL) == 0){
LoadMessage("Service.exe : Start service failed");
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return;
}
LoadMessage("\tService instaled");
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
}
DWORD WINAPI ServiceWorkerThreadEntry(LPVOID lpParam) {
if (isCreate) {
return ERROR_SUCCESS;
}
isCreate = TRUE;
wchar_t ProgramToRun[MAX_PATH];
ZeroMemory(ProgramToRun , sizeof(ProgramToRun));
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, 0, ProgramToRun);
std::wstring tmp = std::wstring(ProgramToRun) + L"\\RemoteController\\MainClient.exe";
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(tmp.c_str(), NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
return ERROR_SUCCESS;
}
Consider the following code:
bool ListFolderContent(const std::wstring& fileName)
{
PIDLIST_ABSOLUTE pidl = nullptr;
if (FAILED(::SHILCreateFromPath(fileName.c_str(), &pidl, nullptr)))
return false;
IShellFolder* pShellfolder = nullptr;
LPCITEMIDLIST pidlRelative = nullptr;
HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, &pidlRelative);
if (FAILED(hr))
{
::CoTaskMemFree(pidl);
return false;
}
IEnumIDList* pEnumIDList = nullptr;
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnumIDList);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
while (1)
{
LPITEMIDLIST pChild = nullptr;
hr = pEnumIDList->Next(1, &pChild, nullptr);
if (FAILED(hr))
{
pShellfolder->Release();
::CoTaskMemFree(pidl);
return false;
}
if (hr == S_FALSE)
break;
wchar_t buffer[MAX_PATH + 1];
if (::SHGetPathFromIDListW(pChild, buffer))
{
::OutputDebugString(buffer);
::OutputDebugString(L"\r\n");
}
}
pShellfolder->Release();
::CoTaskMemFree(pidl);
return true;
}
This code works well and logs the content of the folder owning the given file I pass through the fileName parameter.
However I have an issues with this code: Whatever I pass as file name, the logged path is always C:\Users\Admin\Desktop, and NOT the path to the parent folder I'm iterating, as expected. On the other hand the file names are correct.
Can someone explain me what I'm doing wrong?
You are passing just the last component ("filename") here: SHGetPathFromIDListW(pChild, buffer). Since the desktop is the root you are basically asking to get the filesystem path of [Desktop] [Filename] from the namespace.
There are two solutions:
pShellfolder->GetDisplayNameOf(pChild, SHGDN_FORPARSING, ...)+StrRetToBuf. This is fast since you already have an instance of the folder interface.
Call SHGetPathFromIDList with an absolute (full) pidl. On the pidl from SHILCreateFromPath, call ILCloneFull, ILRemoveLastID and ILCombine(clone, pChild).
HRESULT Example()
{
WCHAR buf[MAX_PATH];
GetWindowsDirectory(buf, MAX_PATH);
PathAppend(buf, L"Explorer.exe");
PIDLIST_ABSOLUTE pidl, pidlFullItem;
HRESULT hr = SHILCreateFromPath(buf, &pidl, nullptr); // %windir%\Explorer.exe
if (FAILED(hr)) return hr;
LPITEMIDLIST pLeaf;
IShellFolder*pShellfolder; // %windir%
hr = SHBindToParent(pidl, IID_IShellFolder, (void**)&pShellfolder, nullptr);
if (SUCCEEDED(hr))
{
IEnumIDList*pEnum;
// Method 1:
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
STRRET sr;
hr = pShellfolder->GetDisplayNameOf(pLeaf, SHGDN_FORPARSING, &sr);
if (SUCCEEDED(hr))
{
hr = StrRetToBuf(&sr, pLeaf, buf, MAX_PATH);
if (SUCCEEDED(hr)) wprintf(L"M1: Item: %s\n", buf);
}
}
pEnum->Release();
}
// Method 2:
ILRemoveLastID(pidl); // %windir%\Explorer.exe => %windir%
hr = pShellfolder->EnumObjects(nullptr, SHCONTF_NONFOLDERS, &pEnum);
if (SUCCEEDED(hr))
{
for (; S_OK == (hr = pEnum->Next(1, &pLeaf, nullptr));)
{
pidlFullItem = ILCombine(pidl, pLeaf); // %windir% + Filename
if (pidlFullItem)
{
hr = SHGetPathFromIDListW(pidlFullItem, buf);
if (SUCCEEDED(hr)) wprintf(L"M2: Item: %s\n", buf);
ILFree(pidlFullItem);
}
}
pEnum->Release();
}
pShellfolder->Release();
}
ILFree(pidl);
return hr;
}
I am trying to implement a local login from my custom Credentials Provider. For that, I try to use the MSV1_0 authentication package, but it keeps failing, yielding an INVALID_PARAMETER status.
The code seems like that:
static void _UnicodeStringPackedUnicodeStringCopy(
const UNICODE_STRING& rus,
PWSTR pwzBuffer,
UNICODE_STRING* pus
) {
pus->Length = rus.Length;
pus->MaximumLength = rus.Length;
pus->Buffer = pwzBuffer;
CopyMemory(pus->Buffer, rus.Buffer, pus->Length);
}
HRESULT LsaInitStringW(PUNICODE_STRING pszDestinationString, PCWSTR pszSourceString)
{
size_t cchLength;
HRESULT hr = StringCchLengthW(pszSourceString, USHORT_MAX, &cchLength);
if (SUCCEEDED(hr))
{
USHORT usLength;
hr = SizeTToUShort(cchLength, &usLength);
if (SUCCEEDED(hr))
{
pszDestinationString->Buffer = (PWCHAR)pszSourceString;
pszDestinationString->Length = usLength * sizeof(WCHAR);
pszDestinationString->MaximumLength = pszDestinationString->Length + 1;
hr = S_OK;
}
}
return hr;
}
HRESULT MsvLogonPack(
const MSV1_0_INTERACTIVE_LOGON& milIn,
BYTE** prgb,
DWORD* pcb
) {
size_t cb = sizeof(milIn)
+ milIn.LogonDomainName.Length
+ milIn.UserName.Length
+ milIn.Password.Length;
MSV1_0_INTERACTIVE_LOGON* milOut = (MSV1_0_INTERACTIVE_LOGON*)CoTaskMemAlloc(cb);
if (!milOut) {
return E_OUTOFMEMORY;
}
milOut->MessageType = milIn.MessageType;
BYTE *pbBuffer = (BYTE*)milOut + sizeof(*milOut);
_UnicodeStringPackedUnicodeStringCopy(milIn.LogonDomainName, (PWSTR)pbBuffer, &milOut->LogonDomainName);
pbBuffer += milOut->LogonDomainName.Length;
_UnicodeStringPackedUnicodeStringCopy(milIn.UserName, (PWSTR)pbBuffer, &milOut->UserName);
pbBuffer += milOut->UserName.Length;
_UnicodeStringPackedUnicodeStringCopy(milIn.Password, (PWSTR)pbBuffer, &milOut->Password);
pbBuffer += milOut->Password.Length;
if (pbBuffer != (BYTE*)milOut + cb) {
return E_ABORT;
}
*prgb = (BYTE*)milOut;
*pcb = cb;
return S_OK;
}
HRESULT GetMsvPackage(ULONG * pulAuthPackage) {
HRESULT hr;
HANDLE hLsa;
NTSTATUS status = LsaConnectUntrusted(&hLsa);
if (SUCCEEDED(HRESULT_FROM_NT(status))) {
ULONG ulAuthPackage;
LSA_STRING lsaszKerberosName;
LsaInitString(&lsaszKerberosName, MSV1_0_PACKAGE_NAME);
status = LsaLookupAuthenticationPackage(hLsa, &lsaszKerberosName, &ulAuthPackage);
if (SUCCEEDED(HRESULT_FROM_NT(status))) {
*pulAuthPackage = ulAuthPackage;
hr = S_OK;
}
else {
hr = HRESULT_FROM_NT(status);
}
LsaDeregisterLogonProcess(hLsa);
}
else {
hr = HRESULT_FROM_NT(status);
}
return hr;
}
HRESULT MyCredential::CompleteAuthentication(CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon) {
HRESULT hr;
pcpcs->clsidCredentialProvider = CLSID_MyProvider;
MSV1_0_INTERACTIVE_LOGON mil;
mil.MessageType = MsV1_0WorkstationUnlockLogon;
hr = LsaInitStringW(&mil.LogonDomainName, L"");
if (SUCCEEDED(hr)) hr = LsaInitStringW(&mil.UserName, L"tester");
if (SUCCEEDED(hr)) hr = LsaInitStringW(&mil.Password, L"12345");
if (SUCCEEDED(hr)) {
hr = MsvLogonPack(mil, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);
if (SUCCEEDED(hr)) {
ULONG ulAuthPackage;
hr = GetMsvPackage(&ulAuthPackage);
if (SUCCEEDED(hr)) {
pcpcs->ulAuthenticationPackage = ulAuthPackage;
}
}
}
return hr;
}
This keeps giving a status of INVALID_PARAMETER, with sub-status 0. I tried replacing the MsV1_0InteractiveLogon with MsV1_0WorkstationUnlockLogon, which got me a status of STATUS_LOGON_FAILURE with sub-status INTERNAL_ERROR.
What would be suggested to solve this issue?
After some research and trial, I figured out the problem. The issue was in the Unicode Strings being absolute, while they are required to be relative to the start of the structure. So I made them relative:
_UnicodeStringPackedUnicodeStringCopy(milIn.LogonDomainName, (PWSTR)pbBuffer, &milOut->LogonDomainName);
milOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
pbBuffer += milOut->LogonDomainName.Length;
_UnicodeStringPackedUnicodeStringCopy(milIn.UserName, (PWSTR)pbBuffer, &milOut->UserName);
milOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
pbBuffer += milOut->UserName.Length;
_UnicodeStringPackedUnicodeStringCopy(milIn.Password, (PWSTR)pbBuffer, &milOut->Password);
milOut->Password.Buffer = (PWSTR)(pbBuffer - (BYTE*)milOut);
pbBuffer += milOut->Password.Length;
This behavior is documented for KERB_CERTIFICATE_LOGON structure, but not for MSV1_0_INTERACTIVE_LOGON, for some reason.
I'm using the following C++ code to get all groups for a user:
(from https://msdn.microsoft.com/en-us/library/windows/desktop/aa746342(v=vs.85).aspx. I just added a few liens to get the group GUID as well)
HRESULT CheckUserGroups(IADsUser *pUser)
{
IADsMembers *pGroups;
HRESULT hr = S_OK;
hr = pUser->Groups(&pGroups);
pUser->Release();
if (FAILED(hr)) return hr;
IUnknown *pUnk;
hr = pGroups->get__NewEnum(&pUnk);
if (FAILED(hr)) return hr;
pGroups->Release();
IEnumVARIANT *pEnum;
hr = pUnk->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum);
if (FAILED(hr)) return hr;
pUnk->Release();
// Enumerate.
BSTR bstr;
VARIANT var;
IADs *pADs;
ULONG lFetch;
IDispatch *pDisp;
VariantInit(&var);
hr = pEnum->Next(1, &var, &lFetch);
while (hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pADs->get_Name(&bstr);
printf("Group belonged: %S\n", bstr);
SysFreeString(bstr);
pADs->get_GUID(&bstr);
printf("Group guid: %S\n", bstr);
SysFreeString(bstr);
pADs->Release();
}
VariantClear(&var);
pDisp = NULL;
hr = pEnum->Next(1, &var, &lFetch);
};
hr = pEnum->Release();
return S_OK;
}
int main()
{
CoInitialize(NULL);
CComPtr<IADsUser> pUser;
std::wstring ADpathName = std::wstring(L"WinNT://domain/user");
if( ADsGetObject(ADpathName.c_str(), IID_IADsUser, (void**)&pUser) == S_OK )
{
CheckUserGroups(pUser);
}
return 0;
}
However, the GUID for all groups is the same and doesn't reflect the real group GUID. why is that?
I faced a problem when trying to save ID2D1Bitmap (that created from ID2D1HwndRenderTarget) to PNG File. The output image is just empty with white color. HRESULT returned from function call EndDraw() is -2003238894.
Thanks for any help.
Here is my code:
HRESULT CImageUtil::SaveBitmapToFile(PCWSTR uri,ID2D1Bitmap* pBitmap,ID2D1RenderTarget* pRenderTarget)
{
HRESULT hr = S_OK;
ID2D1Factory *pD2DFactory = NULL;
IWICBitmap *pWICBitmap = NULL;
ID2D1RenderTarget *pRT = NULL;
IWICBitmapEncoder *pEncoder = NULL;
IWICBitmapFrameEncode *pFrameEncode = NULL;
IWICStream *pStream = NULL;
if (SUCCEEDED(hr))
{
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
}
//
// Create IWICBitmap and RT
//
UINT sc_bitmapWidth = pBitmap->GetSize().width;
UINT sc_bitmapHeight = pBitmap->GetSize().height;
if (SUCCEEDED(hr))
{
hr = m_pWICFactory->CreateBitmap(
sc_bitmapWidth,
sc_bitmapHeight,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnLoad,
&pWICBitmap
);
}
if (SUCCEEDED(hr))
{
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED);
rtProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtProps.usage = D2D1_RENDER_TARGET_USAGE_NONE;
hr = pD2DFactory->CreateWicBitmapRenderTarget(
pWICBitmap,
rtProps,
&pRT
);
}
if (SUCCEEDED(hr))
{
//
// Render into the bitmap
//
pRT->BeginDraw();
pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
pRT->DrawBitmap(pBitmap);
pRT->EndDraw();
}
if (SUCCEEDED(hr))
{
//
// Save image to file
//
hr = m_pWICFactory->CreateStream(&pStream);
}
WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;
if (SUCCEEDED(hr))
{
hr = pStream->InitializeFromFilename(uri, GENERIC_WRITE);
}
if (SUCCEEDED(hr))
{
hr = m_pWICFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder);
}
if (SUCCEEDED(hr))
{
hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
}
if (SUCCEEDED(hr))
{
hr = pEncoder->CreateNewFrame(&pFrameEncode, NULL);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->Initialize(NULL);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->SetSize(sc_bitmapWidth, sc_bitmapHeight);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->SetPixelFormat(&format);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->WriteSource(pWICBitmap, NULL);
}
if (SUCCEEDED(hr))
{
hr = pFrameEncode->Commit();
}
if (SUCCEEDED(hr))
{
hr = pEncoder->Commit();
}
SafeRelease(&pD2DFactory);
SafeRelease(&pWICBitmap);
SafeRelease(&pRT);
SafeRelease(&pEncoder);
SafeRelease(&pFrameEncode);
SafeRelease(&pStream);
return hr;
}
How would you even know if you had an error, since you just swallow errors and continue instead of logging where they came from? You get a non-zero hresult, so first figure out which function it comes from by adding a printf or fprintf after every single function call. And you have a glaring omission in the block:
if (SUCCEEDED(hr))
{
//
// Render into the bitmap
//
pRT->BeginDraw();
pRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
pRT->DrawBitmap(pBitmap);
pRT->EndDraw();
}
if (SUCCEEDED(hr))
You don't bother to assign hr anywhere in there, so you wouldn't even know if any of them are erroring out. Obviously, Clear() and the final png writing work fine, since you get a good file, so it's DrawBitmap or one of the bitmap creation calls that are failing.