I'm trying to create a shared bitmap to share a D3D11Texture2d with Direct2d rendering. After creating the texture and render target I attempt to make a shared bitmap, however the call crashes with a memory access error within d2d1!GetParentTexture. My code as follows:
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D_FEATURE_LEVEL reqFeatureLevels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
CComPtr<ID3D11Device> device;
CComPtr<ID3D11DeviceContext> context;
HRESULT hr = D3D11CreateDevice(
NULL, // specify null to use the default adapter
D3D_DRIVER_TYPE_HARDWARE,
0,
creationFlags, // optionally set debug and Direct2D compatibility flags
reqFeatureLevels, // list of feature levels this app can support
ARRAYSIZE(reqFeatureLevels), // number of possible feature levels
D3D11_SDK_VERSION,
&device, // returns the Direct3D device created
NULL, // returns feature level of device created
&context // returns the device immediate context
);
if (FAILED(hr)) return -1;
CComPtr<ID3D11Texture2D> renderTexture;
CD3D11_TEXTURE2D_DESC textureDesc(DXGI_FORMAT_B8G8R8A8_UNORM, 100, 100, 1, 1, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
textureDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
hr = device->CreateTexture2D(&textureDesc, NULL, &renderTexture);
if (FAILED(hr)) return -1;
CComPtr<IDXGISurface> dxgiSurf;
hr = renderTexture.QueryInterface<IDXGISurface>(&dxgiSurf);
OnHResult(hr, "QueryInterface<IDXGISurface>", return false);
DXGI_SURFACE_DESC desc;
dxgiSurf->GetDesc(&desc);
CComPtr<ID2D1Factory> factory;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory), NULL, (void**)&factory);
if (FAILED(hr)) return -1;
CComPtr<ID2D1RenderTarget> renderTarget;
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE));
hr = factory->CreateDxgiSurfaceRenderTarget(dxgiSurf, &props, &renderTarget);
if (FAILED(hr)) return -1;
CComPtr<ID2D1Bitmap> sharedBitmap;
D2D1_BITMAP_PROPERTIES bitmapProperties = D2D1::BitmapProperties(D2D1::PixelFormat(desc.Format, D2D1_ALPHA_MODE_IGNORE));
hr = renderTarget->CreateSharedBitmap(IID_PPV_ARGS(&dxgiSurf), &bitmapProperties, &sharedBitmap);
if (FAILED(hr)) return -1;
Any ideas why this fails?
You pass IID_PPV_ARGS(&dxgiSurf), as first two parameters of CreateSharedBitmap. This macro expands into
IID_IDXGISurface, reinterpret_cast< void * * >(&dxgiSurf)
while the second parameter should be reinterpret_cast< void * >(p_dxgi_surface)` so an extra pointer dereference happens and program crashes.
Related
I created a D3D11 device and can perform operations such as rendering pictures smoothly, but in order to also support GDI, I tried several methods:
Through swapchain -> GetBuffer(ID3D11Texture2D) -> CreateDxgiSurfaceRenderTarget -> ID2D1GdiInteropRenderTarget -> GetDC, finally get the DC. It runs normally on my Win10, but an exception report when running GetDC on Win7: _com_error.
Via swapchain -> GetBuffer(IDXGISurface1) -> GetDC, same as 1.
I suspect that the ID3D11Texture2D/IDXGISurface1 obtained by GetBuffer on Win7 will have some restrictions on the use of GDI, so I changed to dynamically create a new ID3D11Texture2D by myself, and now use DC alone/D3D11 drawing interface alone It works fine, but if I interoperate, I will find that gdi opertaion is drawn on the custom-created ID3D11Texture2D instead of the back_buffer of swapchain:
_d3d->Clear();
_d3d->DrawImage();
HDC hdc = _d3d->GetDC();
DrawRectangleByGDI(hdc);
_d3d->ReleaseDC();
_d3d->Present();
So how to do it: Whether the D3D or DC methods is drawn, they are all on the same ID3D11Texture2D? This way, it is also convenient for my CopyResource.
HRESULT CGraphRender::Resize(const UINT32& width, const UINT32& height)
{
_back_texture2d = nullptr;
_back_rendertarget_view = nullptr;
_dc_texture2d = nullptr;
_dc_render_target = nullptr;
float dpi = GetDpiFromD2DFactory(_d2d_factory);
//Backbuffer
HRESULT hr = _swap_chain->ResizeBuffers(2, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, _is_gdi_compatible ? DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE : 0);
RETURN_ON_FAIL(hr);
hr = _swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&_back_texture2d);
RETURN_ON_FAIL(hr);
hr = CreateD3D11Texture2D(_d3d_device, width, height, &_dc_texture2d);
RETURN_ON_FAIL(hr);
D3D11_RENDER_TARGET_VIEW_DESC rtv;
rtv.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
rtv.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtv.Texture2D.MipSlice = 0;
hr = _d3d_device->CreateRenderTargetView(_back_texture2d, &rtv, &_back_rendertarget_view);
RETURN_ON_FAIL(hr);
...
}
HRESULT CGraphRender::Clear(float color[])
{
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11RenderTargetView* ref_renderTargetView = _back_rendertarget_view;
immediate_context->OMSetRenderTargets(1, &ref_renderTargetView, nullptr);
immediate_context->ClearRenderTargetView(_back_rendertarget_view, color);
return S_OK;
}
HDC CGraphRender::GetDC()
{
if (_is_gdi_compatible)
{
CComPtr<IDXGISurface1> gdi_surface;
HRESULT hr = _dc_texture2d->QueryInterface(__uuidof(IDXGISurface1), (void**)&gdi_surface);
if (SUCCEEDED(hr))
{
HDC hdc = nullptr;
hr = gdi_surface->GetDC(TRUE, &hdc);
if (SUCCEEDED(hr))
{
return hdc;
}
}
}
return nullptr;
}
HRESULT CGraphRender::CopyTexture(ID3D11Texture2D* dst_texture, ID3D11Texture2D* src_texture, POINT* dst_topleft/* = nullptr*/, POINT* src_topleft/* = nullptr*/)
{
if (!dst_texture && !src_texture)
{
return E_INVALIDARG;
}
CComPtr<ID3D11DeviceContext> immediate_context;
_d3d_device->GetImmediateContext(&immediate_context);
if (!immediate_context)
{
return E_UNEXPECTED;
}
ID3D11Texture2D* dst_texture_real = dst_texture ? dst_texture : _dc_texture2d;
POINT dst_topleft_real = dst_topleft ? (*dst_topleft) : POINT{ 0, 0 };
ID3D11Texture2D* src_texture_real = src_texture ? src_texture : _dc_texture2d;
POINT src_topleft_real = src_topleft ? (*src_topleft) : POINT{ 0, 0 };
D3D11_TEXTURE2D_DESC src_desc = { 0 };
src_texture_real->GetDesc(&src_desc);
D3D11_TEXTURE2D_DESC dst_desc = { 0 };
dst_texture_real->GetDesc(&dst_desc);
if (!dst_topleft_real.x && !src_topleft_real.x && !dst_topleft_real.y && !src_topleft_real.y && dst_desc.Width == src_desc.Width && dst_desc.Height == src_desc.Height)
{
immediate_context->CopyResource(dst_texture_real, src_texture_real);
}
else
{
D3D11_BOX src_box;
src_box.left = min((UINT)src_topleft_real.x, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.top = min((UINT)src_topleft_real.y, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.right = min((UINT)src_box.left + src_desc.Width, (UINT)dst_topleft_real.x + dst_desc.Width);
src_box.bottom = min((UINT)src_box.top + src_desc.Height, (UINT)dst_topleft_real.y + dst_desc.Height);
src_box.front = 0;
src_box.back = 1;
ATLASSERT(src_box.left < src_box.right);
ATLASSERT(src_box.top < src_box.bottom);
immediate_context->CopySubresourceRegion(dst_texture_real, 0, dst_topleft_real.x, dst_topleft_real.y, 0, src_texture_real, 0, &src_box);
}
return S_OK;
}
I don’t think Windows 7 supports what you’re trying to do. Here’s some alternatives.
Switch from GDI to something else that can render 2D graphics with D3D11. Direct2D is the most straightforward choice here. And DirectWrite if you want text in addition to rectangles.
If your 2D content is static or only changes rarely, you can use GDI+ to render into in-memory RGBA device context, create Direct3D11 texture with that data, and render a full-screen triangle with that texture.
You can overlay another Win32 window on top of your Direct3D 11 rendering one, and use GDI to render into that one. The GDI window on top must have WS_EX_LAYERED expended style, and you must update it with UpdateLayeredWindow API. This method is the most complicated and least reliable, though.
Here's my problem:
I'm working on a test project, that initializes Direct2D to draw some stuff.
For now, I am in need of creating BMP background so I looked some tutorials of loading bmp to use it with Direct2D on MSDN site. After some coding and debugging I came to the only problem I can't fully comprehend and, well, I'm stuck here. The problem is simple: I get ACCESS VIOLATION at this line:
pRenderTarget->CreateBitmapFromWicBitmap( pConverter, NULL, ppBitmap);
I fixed all issues I could find out and tested every HRESULT.
here's full code of background.cpp:
`
#include "Background.h"
using namespace D2D1;
Background::Background()
{
pIWICFactory = nullptr;
pDecoder = nullptr;
pSource = nullptr;
pStream = nullptr;
pConverter = nullptr;
ppBitmap = nullptr;
destinationWidth = 0;
destinationHeight = 0;
file_path = L"Background.bmp";
}
bool Background::init(HWND hwnd)
{
CoInitializeEx(0, COINIT_MULTITHREADED);
CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIWICFactory));
pIWICFactory->CreateDecoderFromFilename(file_path, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder);
pIWICFactory->CreateStream(&pStream);
pStream->InitializeFromFilename(file_path, GENERIC_READ);
pDecoder->Initialize(pStream,WICDecodeMetadataCacheOnLoad);
pDecoder->GetFrame(0, &pSource);
pIWICFactory->CreateFormatConverter(&pConverter);
pConverter->Initialize(pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
pRenderTarget->CreateBitmapFromWicBitmap( pConverter, NULL, ppBitmap);
return true;
}
Background::~Background()
{
CoUninitialize();
pIWICFactory->Release();
pDecoder->Release();
pSource->Release();
pStream->Release();
pConverter->Release();
CoUninitialize();
}
`
And here's parent class "Render.cpp"
(there's no connection between how I managed class inheritance and the problem - I tried to create new project that contained only one class including both render and background)
`
#include "Render.h"
using namespace D2D1;
Render::Render()
{
pD2DFactory = nullptr;
pRenderTarget = nullptr;
pGreenBrush = nullptr;
}
bool Render::Init(HWND hwnd)
{
HRESULT hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory );
RECT rc;
GetClientRect(hwnd, &rc);
hr = pD2DFactory->CreateHwndRenderTarget(RenderTargetProperties(), HwndRenderTargetProperties(hwnd, SizeU( rc.right - rc.left, rc.bottom - rc.top)),&pRenderTarget);
if (SUCCEEDED(hr))
pRenderTarget->CreateSolidColorBrush(ColorF(ColorF::Green), &pGreenBrush );
else
return false;
return true;
}
bool Render::Draw(HWND hwnd)
{
RECT rc;
GetClientRect(hwnd, &rc);
pRenderTarget->BeginDraw();
pRenderTarget->FillRectangle(
RectF(
rc.left + 500.0f,
rc.top + 250.0f,
rc.right - 500.0f,
rc.bottom - 500.0f),
pGreenBrush);
HRESULT hr = pRenderTarget->EndDraw();
if (SUCCEEDED(hr))
return true;
else
return false;
}
void Render::ShutDown()
{
if (pD2DFactory)
pD2DFactory->Release();
if (pRenderTarget)
pRenderTarget->Release();
if (pGreenBrush)
pGreenBrush->Release();
}
`
From the double 'pp' I asume you declared ppBitmap; as D2D1Bitmap**, also because you pass it as-value to CreateBitmapFromWicBitmap.
If correct your solution is simple: Declare a ptrP*, not a ptrptrPP**
// in class declaration or c'tor(?)
D2D1Bitmap* pBitmap = nullptr; // instead of D2D1Bitmap**
/// at the point of creation
D2D1wndTarget->CreateBitmapFromWicBitmap(<yourConverter>, NULL, &pBitmap);
In your example you declared it as null-ptr and passed it to a function that takes an address to pointer, resulting in the function reading at 0x000000 resulting in an access violation.
I'm a newbie in the DirectShow world, and I just studied the simple "playcap" sample provided by Microsoft SDK Samples. With this little program I've been able to have a window with my webcam stream.
How can I take two shots from my webcam and compare them (even without saving them on the hard disk) to find which pixels are different?
I easily did this job using Win32API capture windows, but it was very slow, and I need it to be fast.
Thank you in advance, it is very important for my project.
You'd better search here for answer or look in samples for Sample Grabber Filter.
For more details you can write me directly here.
Add the Sample Grabber filter to the graph.
IBaseFilter *pSG_Filter;
hr = CoCreateInstance(
CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pSG_Filter
);
hr = pGraph->AddFilter(pSG_Filter, L"SampleGrab");
Add the Null Renderer filter to the graph.
IBaseFilter *pNull;
hr = CoCreateInstance(
CLSID_NullRenderer,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&pNull
);
hr = pGraph->AddFilter(pNull, L"NullRender");
Now you can use the ICaptureGraphBuilder2::RenderStream method to connect all three filters in one method call, going from the still pin to the Sample Grabber, and from the Sample Grabber to the Null Renderer:
hr = pBuild->RenderStream(
&PIN_CATEGORY_STILL, // Connect this pin ...
&MEDIATYPE_Video, // with this media type ...
pCap, // on this filter ...
pSG_Filter, // to the Sample Grabber ...
pNull); // ... and finally to the Null Renderer.
Now use the ISampleGrabber interface to configure the Sample Grabber so that it buffers samples:
ISampleGrabber *pSG = NULL;
hr = pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG);
if (SUCCEEDED(hr))
{
hr = pSG->SetOneShot(FALSE);
hr = pSG->SetBufferSamples(TRUE);
...
Now, you should look at method ISampleGrabber::SetOneShot and maybe set TRUE there.
Set the callback interface with a pointer to your callback object:
hr = pSG->SetCallback(&g_StillCapCB, 0); // 0 = Use the SampleCB callback method.
Get the media type that the still pin used to connect with the Sample Grabber:
// Store the media type for later use.
AM_MEDIA_TYPE g_StillMediaType;
hr = pSG->GetConnectedMediaType(&g_StillMediaType);
pSG->Release();
This media type will contain the BITMAPINFOHEADER structure that defines the format of the still image.
What follows is an example of the callback class. Note that the class implements IUnknown, which it inherits through the ISampleGrabber interface, but it does not keep a reference count. This is safe because the application creates the object on the stack, and the object remains in scope throughout the lifetime of the filter graph.
All of the work happens in the BufferCB method, which is called by the Sample Grabber whenever it gets a new sample. In the following example, the method writes the bitmap to a file:
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
// Fake referance counting.
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
{
if (NULL == ppvObject) return E_POINTER;
if (riid == __uuidof(IUnknown))
{
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (riid == __uuidof(ISampleGrabberCB))
{
*ppvObject = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
{
return E_NOTIMPL;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)
{
if ((g_StillMediaType.majortype != MEDIATYPE_Video) ||
(g_StillMediaType.formattype != FORMAT_VideoInfo) ||
(g_StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) ||
(g_StillMediaType.pbFormat == NULL))
{
return VFW_E_INVALIDMEDIATYPE;
}
HANDLE hf = CreateFile("C:\\Example.bmp", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hf == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
long cbBitmapInfoSize = g_StillMediaType.cbFormat - SIZE_PREHEADER;
VIDEOINFOHEADER *pVideoHeader =
(VIDEOINFOHEADER*)g_StillMediaType.pbFormat;
BITMAPFILEHEADER bfh;
ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 'MB'; // Little-endian for "BM".
bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
// Write the file header.
DWORD dwWritten = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);
WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
CloseHandle( hf );
return S_OK;
}
};
Free the media type before the application exits:
// On exit, remember to release the media type.
FreeMediaType(g_StillMediaType);
I am trying to program a Direct2D desktop app based on a Windows tutorial, but am having problems creating a SwapChain1. In the code below everything gets initialized until the CreateSwapChainForHwnd. The pointer m_pDXGISwapChain1 stays NULL. All the pointers except pOutput are ComPtrs.
D2D1_FACTORY_OPTIONS options;
ZeroMemory(&options, sizeof(D2D1_FACTORY_OPTIONS));
HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
__uuidof(ID2D1Factory1), &options, &m_pD2DFactory1);
if(SUCCEEDED(hr))
{
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 };
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, creationFlags,
featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &m_pD3DDevice,
&m_featureLevel, &m_pD3DDeviceContext);
}
if(SUCCEEDED(hr))
hr = m_pD3DDevice.As(&m_pDXGIDevice1);
if(SUCCEEDED(hr))
hr = m_pD2DFactory1->CreateDevice(m_pDXGIDevice1.Get(), &m_pD2DDevice);
if(SUCCEEDED(hr))
hr = m_pD2DDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &m_pD2DDeviceContext);
if(SUCCEEDED(hr))
hr = m_pDXGIDevice1->GetAdapter(&m_pDXGIAdapter);
if(SUCCEEDED(hr))
hr = m_pDXGIAdapter->GetParent(IID_PPV_ARGS(&m_pDXGIFactory2));
DXGI_SWAP_CHAIN_DESC1 swapChainDesc1 = {0};
swapChainDesc1.Width = 0;
swapChainDesc1.Height = 0;
swapChainDesc1.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDesc1.Stereo = false;
swapChainDesc1.SampleDesc.Count = 1;
swapChainDesc1.SampleDesc.Quality = 0;
swapChainDesc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc1.BufferCount = 2;
swapChainDesc1.Scaling = DXGI_SCALING_NONE;
swapChainDesc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
swapChainDesc1.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
swapChainDesc1.Flags = 0;
IDXGIOutput *pOutput;
m_pDXGIAdapter->EnumOutputs(0, &pOutput);
if(SUCCEEDED(hr))
hr = m_pDXGIFactory2->CreateSwapChainForHwnd(
static_cast<IUnknown*>(m_pD3DDevice.Get()), m_hwnd, &swapChainDesc1,
NULL, pOutput, &m_pDXGISwapChain1);
if(SUCCEEDED(hr))
hr = m_pDXGIDevice1->SetMaximumFrameLatency(1);
if(SUCCEEDED(hr))
hr = m_pDXGISwapChain1->GetBuffer(0, IID_PPV_ARGS(&m_pDXGIBackBuffer));
If all your pointers are ComPtr, then the call should look like this:
ComPtr<ID3D11Device> d3dDevice;
ComPtr<IDXGIFactory2> dxgiFactory;
// assuming d3dDevice and dxgiFactory are initialized correctly:
ComPtr<IDXGISwapChain1> swapChain;
dxgiFactory->CreateSwapChainForHwnd(d3dDevice.Get(), hWnd, &swapChainDescription, nullptr, nullptr, swapChain.GetAddressOf())
As for your swap chain description, if you're making a non-Windows Store App, you should set
swapChainDescription.Scaling = DXGI_SCALING_STRETCH;
swapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
Both of those values are 0, so you can leave them out.
Here is the complete swap chain description that I use:
DXGI_SWAP_CHAIN_DESC1 swapChainDescription = {};
swapChainDescription.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.BufferCount = 2;
See this article for full a walkthrough of how to set up Direct2D 1.1 properly - including the CreateSwapChainForHwnd call: http://msdn.microsoft.com/en-us/magazine/dn198239.aspx
Direct2D don't have SwapChain at user level, SwapChain is for Direct3D, I see some DirectX 11 code in your post, do you really want Direct2D? or Direct3D?
On Windows XP there is a known way to create a Remote Assistance Ticket.
http://msdn.microsoft.com/en-us/library/ms811079.aspx
But on Vista this does not appear to work. How does one do this on Vista or Windows 7?
There turns out to be two ways. The Microsoft API is called IRASrv and is documented here:
http://msdn.microsoft.com/en-us/library/cc240176(PROT.10).aspx
Another way is to simply call msra.exe. with password and novice params (e.g. msra.exe /saveasfile testfile thepassword). However that does prompt the user with the password dialog.
Here is example code for calling the IRASrv interface and generating a Remote Assistance Connection String.
COSERVERINFO si; ::ZeroMemory( &si, sizeof( si ) );
MULTI_QI qi; ::ZeroMemory( &qi, sizeof( qi ) );
HRESULT hr = S_OK;
BSTR bstrUserName = SysAllocString(L"jon");
BSTR bstrDomainName = SysAllocString(L"");
BSTR bstrPasswordStr = SysAllocString(L"testpass");
// Get the security information entered by the user
_bstr_t bstrUser(bstrUserName);
_bstr_t bstrDomain(bstrDomainName);
_bstr_t bstrPassword(bstrPasswordStr);
// Set AuthIdentity
SEC_WINNT_AUTH_IDENTITY_W AuthIdentity = {
(unsigned short*)bstrUserName,
bstrUser.length(),
(unsigned short*)bstrDomainName,
bstrDomain.length(),
(unsigned short*)bstrPasswordStr,
bstrPassword.length(),
SEC_WINNT_AUTH_IDENTITY_UNICODE
};
COAUTHINFO AuthInfo = {
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_DEFAULT,
NULL,
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // The authentication level used
RPC_C_IMP_LEVEL_IMPERSONATE,
(COAUTHIDENTITY*)&AuthIdentity,
EOAC_NONE
};
si.pAuthInfo = &AuthInfo;
si.pwszName = bstrMachineName;
qi.pIID = &(__uuidof(RAServerLib::IRASrv));
hr = ::CoCreateInstanceEx(
__uuidof(RAServerLib::RASrv), NULL, CLSCTX_REMOTE_SERVER,
&si, 1, &qi );
if (FAILED(hr))
{
return hr;
}
CComPtr<RAServerLib::IRASrv> prasrv;
hr = qi.pItf->QueryInterface(__uuidof(RAServerLib::IRASrv), (void**)&prasrv);
if (FAILED(hr))
{
return hr;
}
LPWSTR pstr=NULL;
hr = prasrv->raw_GetNoviceUserInfo(&pstr);
if (FAILED(hr))
{
return hr;
}
pstr contains the Remote Assistance Connection String (type 2)