What is coming in IDataObject? - c++

When you implement IDropTarget you must implement this:
virtual HRESULT STDMETHODCALLTYPE Drop(
/* [unique][in] */ __RPC__in_opt IDataObject *pDataObj,
/* [in] */ DWORD grfKeyState,
/* [in] */ POINTL pt,
/* [out][in] */ __RPC__inout DWORD *pdwEffect)=0;
I want to know what kind of data is coming in the IDataObject.
I did this:
FORMATETC fdrop = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
if (SUCCEEDED(pDataObj->QueryGetData(&fdrop)) ){
STGMEDIUM stgMedium = {0};
stgMedium.tymed = TYMED_HGLOBAL;
HRESULT hr = pDataObj->GetData(&fdrop, &stgMedium);
if (SUCCEEDED(hr))
{
But this only works when someone drop files. I saw that there's also a CF_TEXT and CF_BITMAP, but I don't want to query for all types of Clipboard Formats, so I want to know if there's a way of querying IDataObject's type of data.
CF_HDROP works fine for files, but when I drop an image from a browser for example, I don't know what kind of CF_ to use... I tried CF_BITMAP but doesn't work.

See IDataObject::EnumFormatEtc. As you can see from the documentation it may be possible to query for the data in multiple formats and EnumFormatEtc is a means to enumerate the various formats available.

Related

WPD get media dimensions

I want to get the width and hight of a image file on a WPD via IPortableDeviceValues.
According to the Windows Dev Center every object whose type is WPD_CONTENT_TYPE_IMAGE (which they are) requires to provide WPD_MEDIA_WIDTH/WPD_MEDIA_HEIGHT but I always get a error.
HRESULT MyPortableDevice::getIntValue(IPortableDeviceProperties* properties, PCWSTR objectID, const PROPERTYKEY& key, DWORD* value)
{
ComPtr<IPortableDeviceValues> objectProperties;
ComPtr<IPortableDeviceKeyCollection> propertiesToRead;
HRESULT hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&propertiesToRead));
if (SUCCEEDED(hr)) {
HRESULT tempHr = S_OK;
tempHr = propertiesToRead->Add(key);
}
if (SUCCEEDED(hr)) {
hr = properties->GetValues(objectID,
propertiesToRead.Get(),
&objectProperties);
}
if (SUCCEEDED(hr)) {
ULONG intValue = 0;
hr = objectProperties->GetUnsignedIntegerValue(key, &intValue);
if (SUCCEEDED(hr)) {
value = &intValue;
intValue = 0;
}
}
return hr;
I always get a error value from
hr = objectProperties->GetUnsignedIntegerValue(key, &intValue);
hr = 0x80070490 and I can't find this error code here
Does anyone know what's wrong?
The error you got is:
Error code: (HRESULT) 0x80070490 (2147943568) - Element not found.
The reason you got this error most probably is that actually phone apps developers usually just ignore some of properties.
I have connected my phone to PC and checked some images with WPD Information Tool , and I get only such fields for .jpg screenshot:
I think in most cases you need to read content of the picture to stream and check it's parameters directly. Maybe in some formats you can read only some "header" part and get WIDTH and HEIGHT from there.

VirtualBox IGuestSession::ProcessCreate returns 0x8000FFFF (E_UNEXPECTED)

So I'm trying to execute a process in the guest session from the host, but I keep getting a 0x8000FFFF (E_UNEXPECTED) HRESULT from it. Since I'm getting a COM error rather than VBOX_E_IPRT_ERROR it makes me think my SAFEARRAYs are the issue and not the actual parameters if that makes sense. I'm not too familiar with COM, so it might just be a case of me using SAFEARRAY wrong. Either way, here's the code I'm trying right now:
SAFEARRAY *args_and_env, *creation_flags;
SAFEARRAYBOUND arrayDim[1];
arrayDim[0].lLbound= 0;
arrayDim[0].cElements= 1;
args_and_env = SafeArrayCreate(VT_LPWSTR,1,arrayDim);
SafeArrayPutElement(args_and_env, 0, L"");
creation_flags = SafeArrayCreate(VT_INT, 1, arrayDim);
int flag = ProcessCreateFlag_None;
SafeArrayPutElement(creation_flags, 0, &flag);
IGuestProcess *proca;
rc = guestSession->ProcessCreate(proc, args_and_env, args_and_env, creation_flags, 0, &proca);
Documentation for IGuestSession::ProcessCreate is as following:
IGuestProcess IGuestSession::processCreate(
[in] wstring executable,
[in] wstring arguments[],
[in] wstring environmentChanges[],
[in] ProcessCreateFlag flags[],
[in] unsigned long timeoutMS)
And the function declaration is as following:
HRESULT STDMETHODCALLTYPE ProcessCreate(
/* [in] */ BSTR aExecutable,
/* [in] */ SAFEARRAY * aArguments,
/* [in] */ SAFEARRAY * aEnvironmentChanges,
/* [in] */ SAFEARRAY * aFlags,
/* [in] */ ULONG aTimeoutMS,
/* [retval][out] */ IGuestProcess **aGuestProcess)
I've also tried passing NULL to both arguments and environmentChanges as I'm not looking to use any of them, but with the same result.
When i tested my task i realized that this problem can be if you use session OS without password. You have to set password and create session with password:
BSTR login = ...;
BSTR passsword = ...;
BSTR empty = SysAllocString(L"");
HRESULT rc = guest->CreateSession(login, password, empty, sessionName, &guestSession);
And then create a guest process

Problems understanding and using double pointers

I am not sure how to use double pointers.
The function i need to use looks as following:
HRESULT GetBuffer(
[out] IMediaSample **ppBuffer,
[in] REFERENCE_TIME *pStartTime,
[in] REFERENCE_TIME *pEndTime,
[in] DWORD dwFlags
);
Documentation says:
ppBuffer [out]
Receives a pointer to the buffer's IMediaSample interface. The caller must release the interface.
This is what i tried using it:
HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
HRESULT hr = NO_ERROR;
myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
if (sample->GetActualDataLength() > 0)
{
IMediaSample **outsample;
m_pAllocator->GetBuffer(outsample, NULL, NULL, NULL); //Access violation here
BYTE** sampleBuffer;
BYTE** newBuffer;
sample->GetPointer(sampleBuffer);
(*outsample)->GetPointer(newBuffer);
memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(**sampleBuffer));
m_pInputPin->Receive(*outsample);
sample->AddRef();
}
return hr;
//Forward to filter
}
Which gives me an:
Access violation reading location 0xFFFFFFFFFFFFFFFF.
Then i tried using the address operator:
hr = m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL); //outsample is set to NULL
BYTE* sampleBuffer = NULL;
BYTE* newBuffer = NULL;
sample->GetPointer(&sampleBuffer);
outsample->GetPointer(&newBuffer);
memcpy((void *)newBuffer, (void *)sampleBuffer, sizeof(*sampleBuffer));
m_pInputPin->Receive(outsample);
This sets outsample to NULL.
So what is the correct syntax to handle double pointers?
My first, high-level comment, is that you are not checking the return values of the functions that you call. It's a mistake to neglect error checking. Your first step is to add the necessary error checking.
HRESULT GetBuffer(
[out] IMediaSample **ppBuffer,
[in] REFERENCE_TIME *pStartTime,
[in] REFERENCE_TIME *pEndTime,
[in] DWORD dwFlags
);
The first parameter is used to return a IMediaSample* to the caller. You need to declare a variable of type IMediaSample*, and pass its address:
IMediaSample* sample;
....
hr = m_pAllocator->GetBuffer(&outsample, ...);
// check hr
....
So, outsample is of type IMediaSample*. When you take its address, with &outsample, you now have something of type IMediaSample**, which is what you need.
Remember that when working with interfaces, you always work with a pointer to the interface.
You've made the same mistake with the BYTE** parameters. Again, declare variables of type BYTE*, and pass the address of these variables to the functions that you call.
BYTE* sampleBuffer;
BYTE* newBuffer;
....
hr = sample->GetPointer(&sampleBuffer);
// check hr
hr = outsample->GetPointer(newBuffer);
// check hr
Using sizeof(**sampleBuffer) in your call to memcpy is wrong. In your code, where sampleBuffer is wrongly declared as BYTE**, sizeof(**sampleBuffer) is just sizeof(BYTE) which is always 1.
In fact you can conclude that any use of sizeof is incorrect here because sizeof is evaluated at compile time. You need to find the actual size of the dynamic buffer at runtime using whatever functionality these interfaces provide.
The call to sample->AddRef() looks a little suspect. I don't see any evidence that anything has taken a new reference to the interface.
IMediaSample **outsample;
m_pAllocator->GetBuffer(outsample, NULL, NULL, NULL);
You're passing the function the value of outsample, which is a garbage value since it doesn't point to anything. You want:
IMediaSample *outsample;
m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL);
This gives the function the address of outsample so that it can stuff the pointer it wants to return in it.
I try to simulate the function as test, which using int** as output . the problem here is the function is suppose *output is is valid, so in the first way ,you have to make sure that, you might want to do something as this
sample = new IMediaSample[1]
this is my sample code, hope it helps
#include <iostream>
using namespace std;
void test(int** output ,int* in)
{
*output = new int[1];
output[0][0] = in[0];
}
int main()
{
int a[] ={ 2 };
int* out1;
test(&out1 ,a);
cout << out1[0] << endl;
int** out2;
out2 = new int*[1];
test(out2 ,a);
cout << out2[0][0] << endl;
return 0;
}

COM server as windows service, cannot pass array as function argument

I'm implementing COM server (using ATL) as Windows service. I have the following method defined in service header:
STDMETHOD(SetBytes)(long lenSource, const BYTE* pSource, VARIANT_BOOL *pResult);
This method is declared in the IDL file:
[
object,
uuid(351C5A5F-3EB8-4CC5-AB79-6DCD27C2F7E0),
dual,
pointer_default(unique)
]
interface ISampleInterface: IUnknown {
HRESULT SetBytes([in] long lenSource, [in,ref,size_is(lenSource)] const BYTE* pSource, [out,retval] VARIANT_BOOL *pResult);
};
I'm calling it from my test application like this:
CoInitialize(NULL);
IUnknownPtr unknown_ptr;
HRESULT hr = unknown_ptr.CreateInstance(__uuidof(MyLib::SampleManager));
if (FAILED(hr)) {
...
};
MyLib::ISampleInterfacePtr sample_ptr;
sample_ptr = unknown_ptr; // no check here, assume sample_ptr is not null
VARIANT_BOOL function_result = VARIANT_FALSE;
vector<uint8_t> flash_data(1000, 2);
function_result = sample_ptr->SetBytes(flash_data.size(), &flash_data[0]);
I'm registering service by performing:
MyService.exe /regserver
MyService.exe -service
Then I'm executing test code step by step. When I'm going to tli file where we can see the following
HRESULT _hr = raw_SetBytes(lenSource, pSource, &_result);
pSource is absolutely ok and points to the area of memory where my data is contained. But when I'm going further (I'm attached to the service with debugger) and I'm in service's function SetBytes, only one byte from this array is contained in memory area and this pointer points to the different address.
I have tried implementing server via dll (it's registered in the system with regsvr32 [dllname]) and the pointer was absolutely ok in it in this case and all the length was passed, not only one byte.
I'm new to COM technology and wondering where I am wrong.
you could maybe wrap your BYTE array it into a SAFEARRAY.
STDMETHODIMP MyClass::getVariantFromCharArray( char *inputCharArray, UINT inputCharArrayLength, VARIANT *outputVariant)
{
SAFEARRAYBOUND saBound;
char *pData = NULL;
saBound.cElements = inputCharArrayLength;
saBound.lLbound = 0;
VariantInit( outputVariant);
(*outputVariant).vt = VT_UI1 | VT_ARRAY;
(*outputVariant).parray = SafeArrayCreate( VT_UI1, 1, &saBound);
if ( (*outputVariant).parray)
{
SafeArrayAccessData( (*outputVariant).parray, (void **)&pData);
memcpy( pData, inputCharArray, inputCharArrayLength);
SafeArrayUnaccessData( (*outputVariant).parray);
return S_OK;
}
else
{
return E_OUTOFMEMORY;
}
}
You need to use a SAFEARRAY to pass byte arrays around in COM.

overriding GetSecurityId in IInternetSecurityManager

I have built an executable which launches a dialog box in which is embedded the IE web browser active-x control (C++).
I want this control to allow cross site scripting. One frame on the web page loads local html, the other loads from a server. I then want the server page to call a javascript function that lives in the local html file.
I am trying to achieve this by having the control implement it's own "IInternetSecurityManager" interface in which I am providing my own ProcessUrlAction and GetSecurityId methods.
From what I've read, what I need to do is make GetSecurityId return the same domain for all urls. My custom implementations are getting called, but no matter what I do, I get the "Permission denied" error when the server html tries to access script on the local html file. Below are my implementations. Does anyone see anything wrong?
#define SECURITY_DOMAIN "http:www.mysite.com"
STDMETHOD (GetSecurityId)(
LPCWSTR pwszUrl,
BYTE *pbSecurityId,
DWORD *pcbSecurityId,
DWORD_PTR dwReserved)
{
if (*pcbSecurityId >=512)
{
memset(pbSecurityId,0,*pcbSecurityId);
strcpy((char*)pbSecurityId,SECURITY_DOMAIN);
pbSecurityId[strlen(SECURITY_DOMAIN)] = 3;
pbSecurityId[strlen(SECURITY_DOMAIN)+1] = 0;
pbSecurityId[strlen(SECURITY_DOMAIN)+2] = 0;
pbSecurityId[strlen(SECURITY_DOMAIN)+3] = 0;
*pcbSecurityId = (DWORD)strlen(SECURITY_DOMAIN)+4;
return S_OK;
}
return INET_E_DEFAULT_ACTION;
}
STDMETHOD(ProcessUrlAction)(
/* [in] */ LPCWSTR pwszUrl,
/* [in] */ DWORD dwAction,
/* [size_is][out] */ BYTE __RPC_FAR *pPolicy,
/* [in] */ DWORD cbPolicy,
/* [in] */ BYTE __RPC_FAR *pContext,
/* [in] */ DWORD cbContext,
/* [in] */ DWORD dwFlags,
/* [in] */ DWORD dwReserved)
{
DWORD dwPolicy=URLPOLICY_ALLOW;
if ( cbPolicy >= sizeof (DWORD))
{
*(DWORD*) pPolicy = dwPolicy;
return S_OK;
}
return INET_E_DEFAULT_ACTION;
}
By delegating these functions to the normal security manager and having a look at the structures the normal security manager fills in, I was able to determine that my issue was in GetSecurityId. For my purposes, I wanted to set the security domain to be a local file for all comers.
#define SECURITY_DOMAIN "file:"
if (*pcbSecurityId >=512)
{
memset(pbSecurityId,0,*pcbSecurityId);
strcpy((char*)pbSecurityId,SECURITY_DOMAIN);
pbSecurityId[strlen(SECURITY_DOMAIN)+1] = 0;
pbSecurityId[strlen(SECURITY_DOMAIN)+2] = 0;
pbSecurityId[strlen(SECURITY_DOMAIN)+3] = 0;
pbSecurityId[strlen(SECURITY_DOMAIN)+4] = 0;
*pcbSecurityId = (DWORD)strlen(SECURITY_DOMAIN)+4;
}