Getting the Address of a function that can only be called - c++

I already asked a Question but I think thats very special and will not get a concrete answer.
Im trying to give a simpler Explanation of what i need help with.
The Issue is that d3d12::pCommandList->CopyTextureRegion; doesnt work because CopyTextureRegion is a function that can only be called, but i need the address of it.
For example this will give me the Address of the ID3D12GraphicsCommandList: d3d12::pCommandList;
This is a small part of my code:
namespace d3d12
{
IDXGISwapChain3* pSwapChain;
ID3D12Device* pDevice;
ID3D12CommandQueue* pCommandQueue;
ID3D12Fence* pFence;
ID3D12DescriptorHeap* d3d12DescriptorHeapBackBuffers = nullptr;
ID3D12DescriptorHeap* d3d12DescriptorHeapImGuiRender = nullptr;
ID3D12DescriptorHeap* pSrvDescHeap = nullptr;;
ID3D12DescriptorHeap* pRtvDescHeap = nullptr;;
ID3D12GraphicsCommandList* pCommandList;
FrameContext* FrameContextArray;
ID3D12Resource** pID3D12ResourceArray;
D3D12_CPU_DESCRIPTOR_HANDLE* RenderTargetDescriptorArray;
HANDLE hSwapChainWaitableObject;
HANDLE hFenceEvent;
UINT NUM_FRAMES_IN_FLIGHT;
UINT NUM_BACK_BUFFERS;
UINT frame_index = 0;
UINT64 fenceLastSignaledValue = 0;
}
d3d12::pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d12::FrameContextArray[0].CommandAllocator, NULL, IID_PPV_ARGS(&d3d12::pCommandList));
// issue, CopyTextureRegion can only be called. I need the address of it
auto RegionHookAddress = d3d12::pCommandList->CopyTextureRegion;

Taking the address of the member function:
auto RegionHookAddress = &d3d12::ID3D12GraphicsCommandList::CopyTextureRegion;
Calling the member function:
(d3d12::pCommandList->*RegionHookAddress)(...);

Related

Storport Virtual Miniport Driver stopping on AdapterControl

Why my StorPort Virtual Miniport Driver (KMDF) stops working after it's AdapterControl function is first called?
Currently, the following is happening after the driver is implemented (WinDbg):
DriverEntry is called. No errors.
HwFindAdapter is called. No errors.
HwInitialize is called. No errors.
HwStartIo is called. No errors. Parameter PSCSI_REQUEST_BLOCK ("SRB") -> Function is SRB_FUNCTION_STORAGE_REQUEST_BLOCK (this is OK for me because in the HwFindAdapter routine, I defined PPORT_CONFIGURATION_INFORMATION -> SrbType to equal SRB_TYPE_STORAGE_REQUEST_BLOCK).
AdapterControl is called. No errors. Parameter SCSI_ADAPTER_CONTROL_TYPE is called with ControlType ScsiQuerySupportedControlTypes (as is default behavior according to MS documentation for the first call).
And that's it. No more calls, and I couldn't find anything related in EventLog. As far as I know, at this point the StorPort sould make another call to my driver's AdapterControl routine and "ask" me to define a device.
--
Please note that the following is not the actual full code, but rather a structural overview:
DriverEntry (
_In_ PVOID DriverObject,
_In_ PVOID RegistryPath
)
{
HW_INITIALIZATION_DATA initdata = { 0 }
initdata.HwFindAdapter = HwFindAdapter;
initdata.HwInitialize = HwInitialize;
initdata.HwAdapterControl = AdapterControl;
initdata.HwResetBus = HwResetBus;
initdata.HwStartIo = HwStartIo;
initdata.HwFreeAdapterResources = HwFreeAdapterResources;
initdata.AdapterInterfaceType = Internal;
initdata.MultipleRequestPerLu = TRUE;
initdata.PortVersionFlags = 0;
status = StorPortInitialize(
DriverObject,
RegistryPath,
&initdata,
NULL
);
return status;
}
|
HwFindAdapter (AdapterExtension, HwContext, BusInformation, ArgumentString, ConfigInfo, Reserved3)
{
//ConfigInfo is referenced to PPORT_CONFIGURATION_INFORMATION in the parameters above.
ConfigInfo->AlignmentMask = FILE_BYTE_ALIGNMENT;
ConfigInfo->NumberOfBuses = 1
ConfigInfo->CachesData = FALSE;
ConfigInfo->MapBuffers = STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE;
ConfigInfo->MaximumNumberOfTargets = 255;
ConfigInfo->SrbType = SRB_TYPE_STORAGE_REQUEST_BLOCK;
ConfigInfo->AddressType = STORAGE_ADDRESS_TYPE_BTL8;
ConfigInfo->SynchronizationModel = StorSynchronizeFullDuplex;
ConfigInfo->HwMSInterruptRoutine = NULL;
ConfigInfo->InterruptSynchronizationMode = InterruptSupportNone;
ConfigInfo->VirtualDevice = TRUE;
ConfigInfo->DumpMode = DUMP_MODE_RESUME;
ConfigInfo->MaxNumberOfIO = 100;
ConfigInfo->BusResetHoldTime = 0;
ConfigInfo->FeatureSupport = 0x7f;
return SP_RETURN_FOUND;
}
HwInitialize is there but does nothing except returning STATUS_SUCCESS.
|
HwStartIo (
_In_ PVOID DeviceExtension,
_In_ PSCSI_REQUEST_BLOCK Srb
)
{
//Currently does nothing with data, as is not needed for now.
StorPortNotification(RequestComplete, DeviceExtension, Srb);
return TRUE;
}
|
AdapterControl (
_In_ PVOID DeviceExtension,
_In_ SCSI_ADAPTER_CONTROL_TYPE ControlType,
_In_ PVOID Parameters
)
{
PSCSI_SUPPORTED_CONTROL_TYPE_LIST controlTypeList;
switch (ControlType)
{
case ScsiQuerySupportedControlTypes:
controlTypeList = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters; // get pointer to control type list
controlTypeList->SupportedTypeList[ScsiQuerySupportedControlTypes] = TRUE;
controlTypeList->SupportedTypeList[ScsiStopAdapter] = TRUE;
controlTypeList->SupportedTypeList[ScsiRestartAdapter] = TRUE;
controlTypeList->SupportedTypeList[ScsiSetBootConfig] = TRUE;
//referenced cases are defined but not relevant for now.
}
return ScsiAdapterControlSuccess;
}
HwFreeAdapterResources is there but does nothing, and returns nothing because it is a VOID.
OK, so I found out what was wrong.
HwStartIo was called, but with value PSCSI_REQUEST_BLOCK->Function == "SRB_FUNCTION_PNP".
This indicates an error on any function called beforehand, in my case I had a wrong return code set (Function HwInitialize: I returned "STATUS_SUCCESS" (0xL) instead of "TRUE" (0x0).)
In normal operation, upon first initialization, PSCSI_REQUEST_BLOCK->Function should equal "SRB_FUNCTION_EXECUTE_SCSI" to gather SCSI Bus-, Target- and LUN information.

How to use Win32 ThreadPool API?

This version (based on this article) works:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
VOID
CALLBACK
MyWorkCallback(
PTP_CALLBACK_INSTANCE Instance,
PVOID Parameter,
PTP_WORK Work
)
{
// Instance, Parameter, and Work not used in this example.
UNREFERENCED_PARAMETER(Instance);
UNREFERENCED_PARAMETER(Parameter);
UNREFERENCED_PARAMETER(Work);
DWORD threadId = GetCurrentThreadId();
BOOL bRet = FALSE;
//
// Do something when the work callback is invoked.
//
{
_tprintf(_T("MyWorkCallback: ThreadId = %d Task performed.\n"), threadId);
}
return;
}
int main()
{
TP_CALLBACK_ENVIRON CallBackEnviron;
PTP_POOL pool = NULL;
PTP_CLEANUP_GROUP cleanupgroup = NULL;
PTP_WORK_CALLBACK workcallback = MyWorkCallback;
PTP_TIMER timer = NULL;
PTP_WORK work = NULL;
InitializeThreadpoolEnvironment(&CallBackEnviron);
pool = CreateThreadpool(NULL);
SetThreadpoolThreadMaximum(pool, 1);
SetThreadpoolThreadMinimum(pool, 3);
cleanupgroup = CreateThreadpoolCleanupGroup();
SetThreadpoolCallbackPool(&CallBackEnviron, pool);
SetThreadpoolCallbackCleanupGroup(&CallBackEnviron, cleanupgroup, NULL);
work = CreateThreadpoolWork(workcallback, NULL, &CallBackEnviron);
for (int i = 0; i < 10; ++i)
{
SubmitThreadpoolWork(work);
}
}
However, this version also works (with the same work function from above):
int main()
{
PTP_WORK = CreateThreadpoolWork(workcallback, NULLPTR, NULLPTR);
for (int i = 0; i < 10; ++i)
{
SubmitThreadpoolWork(work);
}
}
What are the differences between the two versions (except for the minimum and maximum thread count)?
Why would I use one version over another?
This is covered in the documentation for InitializeThreadpoolEnvironment:
Create a callback environment if you plan to call one of the following functions to modify the environment:
SetThreadpoolCallbackCleanupGroup
SetThreadpoolCallbackLibrary
SetThreadpoolCallbackPool
SetThreadpoolCallbackPriority
SetThreadpoolCallbackRunsLong
If you need the functionality provided by one or more of the listed functions, then you need to create a callback environment. If you don't, you don't.
If in doubt when starting a new project, use the simple approach to begin with, and see whether it meets your needs. You can always go back and switch to the more complex variant if and when it becomes necessary.

WinRT C++ (Win10) Accessing bytes from SoftwareBitmap / BitmapBuffer

To process my previewFrames of my camera in OpenCV, I need access to the raw Pixel data / bytes. So, there is the new SoftwareBitmap, which should exactly provide this.
There is an example for c#, but in visual c++ I can't get the IMemoryBufferByteAccess (see remarks) Interface working.
Code with Exceptions:
// Capture the preview frame
return create_task(_mediaCapture->GetPreviewFrameAsync(videoFrame))
.then([this](VideoFrame^ currentFrame)
{
// Collect the resulting frame
auto previewFrame = currentFrame->SoftwareBitmap;
auto buffer = previewFrame->LockBuffer(Windows::Graphics::Imaging::BitmapBufferAccessMode::ReadWrite);
auto reference = buffer->CreateReference();
// Get a pointer to the pixel buffer
byte* pData = nullptr;
UINT capacity = 0;
// Obtain ByteAccess
ComPtr<IUnknown> inspectable = reinterpret_cast<IUnknown*>(buffer);
// Query the IBufferByteAccess interface.
Microsoft::WRL::ComPtr<IMemoryBufferByteAccess> bufferByteAccess;
ThrowIfFailed(inspectable.As(&bufferByteAccess)); // ERROR ---> Throws HRESULT = E_NOINTERFACE
// Retrieve the buffer data.
ThrowIfFailed(bufferByteAccess->GetBuffer(_Out_ &pData, _Out_ &capacity)); // ERROR ---> Throws HRESULT = E_NOINTERFACE, because bufferByteAccess is null
I tried this too:
HRESULT hr = ((IMemoryBufferByteAccess*)reference)->GetBuffer(&pData, &capacity);
HRESULT is ok, but I can't access pData -> Access Violation reading Memory.
Thanks for your help.
You should use reference instead of buffer in reinterpret_cast.
#include "pch.h"
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
MIDL_INTERFACE("5b0d3235-4dba-4d44-865e-8f1d0e4fd04d")
IMemoryBufferByteAccess : IUnknown
{
virtual HRESULT STDMETHODCALLTYPE GetBuffer(
BYTE **value,
UINT32 *capacity
);
};
auto previewFrame = currentFrame->SoftwareBitmap;
auto buffer = previewFrame->LockBuffer(BitmapBufferAccessMode::ReadWrite);
auto reference = buffer->CreateReference();
ComPtr<IMemoryBufferByteAccess> bufferByteAccess;
HRESULT result = reinterpret_cast<IInspectable*>(reference)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));
if (result == S_OK)
{
WriteLine("Get interface successfully");
BYTE* data = nullptr;
UINT32 capacity = 0;
result = bufferByteAccess->GetBuffer(&data, &capacity);
if (result == S_OK)
{
WriteLine("get data access successfully, capacity: " + capacity);
}
}
Based on answer from #jeffrey-chen and example from #kennykerr, I've assembled a tiny bit cleaner solution:
#include <wrl/client.h>
// other includes, as required by your project
MIDL_INTERFACE("5b0d3235-4dba-4d44-865e-8f1d0e4fd04d")
IMemoryBufferByteAccess : ::IUnknown
{
virtual HRESULT __stdcall GetBuffer(BYTE **value, UINT32 *capacity) = 0;
};
// your code:
auto previewFrame = currentFrame->SoftwareBitmap;
auto buffer = previewFrame->LockBuffer(BitmapBufferAccessMode::ReadWrite);
auto bufferByteAccess= buffer->CreateReference().as<IMemoryBufferByteAccess>();
WriteLine("Get interface successfully"); // otherwise - exception is thrown
BYTE* data = nullptr;
UINT32 capacity = 0;
winrt::check_hresult(bufferByteAccess->GetBuffer(&data, &capacity));
WriteLine("get data access successfully, capacity: " + capacity);
I'm currently accessing the raw unsigned char* data from each frame I obtain on a MediaFrameReader::FrameArrived event without using WRL and COM...
Here it is how:
void MainPage::OnFrameArrived(MediaFrameReader ^reader, MediaFrameArrivedEventArgs ^args)
{
MediaFrameReference ^mfr = reader->TryAcquireLatestFrame();
VideoMediaFrame ^vmf = mfr->VideoMediaFrame;
VideoFrame ^vf = vmf->GetVideoFrame();
SoftwareBitmap ^sb = vf->SoftwareBitmap;
Buffer ^buff = ref new Buffer(sb->PixelHeight * sb->PixelWidth * 2);
sb->CopyToBuffer(buff);
DataReader ^dataReader = DataReader::FromBuffer(buffer);
Platform::Array<unsigned char, 1> ^arr = ref new Platform::Array<unsigned char, 1>(buffer->Length);
dataReader->ReadBytes(arr);
// here arr->Data is a pointer to the raw pixel data
}
NOTE: The MediaCapture object needs to be configured with MediaCaptureMemoryPreference::Cpu in order to have a valid SoftwareBitmap
Hope the above helps someone

Can't allocate a pointer to object of abstract type?

For some reason, I'm not able to initialize a set of pointers to an abstract data type like so:
gkAnimation* run = NULL, walk = NULL, idle = NULL;
I'm getting an error saying:
jni/STEP3D_GK_Wrapper_JNI.cpp:283:34: error: cannot allocate an object of abstract type 'gkAnimation'
I haven't had this issue happen before, and I don't think the class itself is doing anything special for this error to happen or that it would matter. I can post more code if it helps, but I'm pretty stumped here. Any ideas?
The problem is that this syntax:
gkAnimation* run = NULL, walk = NULL, idle = NULL;
Does not mean:
gkAnimation* run = NULL;
gkAnimation* walk = NULL;
gkAnimation* idle = NULL;
It means:
gkAnimation* run = NULL;
gkAnimation walk = NULL; /* invalid */
gkAnimation idle = NULL; /* invalid */
You need to explicitly define each item in the list as a pointer:
gkAnimation *run = NULL, *walk = NULL, *idle = NULL;
This is why many prefer the syntax style of placing the pointer next to the variable rather than next to the type.

ChangeDisplaySettingsEx() always returns DISP_CHANGE_BADPARAM

I am attempting to set the Display Mode of my Monitor using WinAPI C++ functions.
My Problem: Calling ChangeDisplaySettingsEx() always returns DISP_CHANGE_BADPARAM. What am I doing wrong?
I think it may be my devMode.dmDriverExtra value thats causing the error. I've read MSDN and the explaination of devMode.dmDriverExtra is confusing. What is it and how do I find out the Monitors' dmDriverExtra?
Whats causing my code below to always return DISP_CHANGE_BADPARAM?
DEVMODE devMode;
POINTL p = {0,0};
_tcscpy(devMode.dmDeviceName, _T("\\Device\\00000072"));
devMode.dmSpecVersion = DM_SPECVERSION;
devMode.dmDriverVersion = 1; // How do I determine the driver version?
devMode.dmSize = sizeof(DEVMODE);
devMode.dmDriverExtra = 0x5c0000; //
devMode.dmFields = DM_POSITION;
devMode.dmPosition = p;
LONG res = ChangeDisplaySettingsEx(_T("\\Device\\00000072"), &devMode, mainHwnd, 0, NULL);
_tprintf(_T("%s: %d\n\n\n"), _T("\\Device\\00000072"), res);
// The above printf always prints out "\Device\00000072: -5" (DISP_CHANGE_BADPARAM=-5)
The hwnd parameter is documented to be reserved and must be NULL. Additionally dmDriverExtra is a 16 bit value, so 0x5c0000 doesn't fit.