I'm tasked with solving the following issue: My application crashes when running on a 64 bit machine when the PrintDlg() function is called.
After digging and hair pulling, I've decided the best solution is to replace the original calls of PrintDlg() with its bigger brother, PrintDlgEx().
Doing so fixes one problem (it no longer crashes!), but causes another. When I execute the code, it is not showing the print dialog, just returning a success code, and giving me all of the information for my default printer. I need this function to show the standard "print setup" window, I don't know how the heck to make it happen. Shown below are the sample values I'm trying to use to get my dialog to show.
Any thoughts? Thanks in advance.
// Initialize the PRINTDLGEX structure.
pd2.lStructSize = sizeof(PRINTDLGEX);
pd2.hwndOwner = wnddata->wnd.hnd;
pd2.hDevMode = NULL;
pd2.hDevNames = NULL;
pd2.hDC = NULL;
pd2.Flags = PD_RETURNDC | PD_COLLATE;
pd2.Flags2 = 0;
pd2.ExclusionFlags = 0;
pd2.nPageRanges = 0;
pd2.nMaxPageRanges = 10;
pd2.lpPageRanges = NULL;
pd2.nMinPage = 1;
pd2.nMaxPage = 1000;
pd2.nCopies = 1;
pd2.hInstance = 0;
pd2.lpPrintTemplateName = NULL;
pd2.lpCallback = NULL;
pd2.nPropertyPages = 0;
pd2.lphPropertyPages = NULL;
pd2.nStartPage = START_PAGE_GENERAL;
pd2.dwResultAction = 0;
pdrc = PrintDlgEx (&pd2);
You are most likely getting a return code of E_INVALIDARG, due to failure to read the fine print on the PRINTDLGEX structure. Specifically, it says "If the PD_NOPAGENUMS flag is not specified, lpPageRanges must be non-NULL."
The underlying problem with PrintDlg / PrintDlgEx is due to a missing attribute on your WinMain. You need to tag WinMain as [STAThreadAttribute] to indicate that your COM threading model is single-threaded apartment. Other threading models MAY work, but I can't say for sure.
Related
I'm trying to use realloc function in C, to dynamically operate on a char array of strings (char**).
I usually get a realloc():invalid old size error after 41st cicle of the for loop and I really can't understand why.
So, thanks to everyone who will help me ^-^
[EDIT] I'm trying to make the post more clear and following your advices, as a "new active member" of this community, so thank you all!
typedef struct _WordsOfInterest { // this is in an header file containing just
char **saved; // the struct and libraries
int index;
} wordsOfInterest;
int main() {
char *token1, *token2, *save1 = NULL, file[LEN], *temp, *word, **tokenArr;
int n=0, ch,ch2, flag=0, size, init=0,position,currEdit,init2=0,tempEdit,size_arr=LEN,
oldIndex=0,totalIndex=0,*editArr,counterTok=0;
wordsOfInterest toPrint;
char **final;
toPrint.index = 0;
toPrint.saved = malloc(sizeof(char*)*LEN);
editArr = malloc(sizeof(int)*LEN);
tokenArr = malloc(sizeof(char*)*LEN);
final = malloc(sizeof(char*)*1);
// external for loop
for(...) {
tokenArr[counterTok] = token1;
// internal while loop
while(...) {
// some code here surely not involved in the issue
} else {
if(init2 == 0) {
currEdit = config(token1,token2);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
init2 = 1;
} else {
if((abs((int)strlen(token1)-(int)strlen(token2)))<=currEdit) {
if((tempEdit = config(token1,token2)) == currEdit) {
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
if(toPrint.index == size_arr-1) {
size_arr = size_arr*2;
toPrint.saved = realloc(toPrint.saved, size_arr);
}
} else if((tempEdit = config(token1,token2))<currEdit) {
freeArr(toPrint, size_arr);
toPrint.saved[toPrint.index] = token2;
toPrint.index++;
currEdit = tempEdit;
}
}
}
flag = 0;
word = NULL;
temp = NULL;
freeArr(toPrint, size_arr);
}
}
editArr[counterTok] = currEdit;
init2 = 0;
totalIndex = totalIndex + toPrint.index + 1;
final = realloc(final, (sizeof(char*)*totalIndex));
uniteArr(toPrint, final, oldIndex);
oldIndex = toPrint.index;
freeArr(toPrint,size_arr);
fseek(fp2,0,SEEK_SET);
counterTok++;
}
You start with final uninitialized.
char **final;
change it to:
char **final = NULL;
Even if you are starting with no allocation, it needs a valid value (e.g. NULL) because if you don't initialize a local variable to NULL, it gets garbage, and realloc() will think it is reallocating a valid chunk of memory and will fail into Undefined Behaviour. This is probably your problem, but as you have eliminated a lot of code in between the declaration and the first usage of realloc, whe cannot guess what is happening here.
Anyway, if you have indeed initialized it, I cannot say, as you have hidden part of the code, unlistening the recommendation of How to create a Minimal, Reproducible Example
.
There are several reasons (mostly explained there) to provide a full but m inimal, out of the box, failing code. This allows us to test that code without having to provide (and probably solving, all or part) the neccesary code to make it run. If you only post a concept, you cannot expect from us complete, full running, and tested code, degrading strongly the quality of SO answers.
This means you have work to do before posting, not just eliminating what you think is not worth mentioning.
You need to build a sample that, with minimum code, shows the actual behaviour you see (a nonworking complete program) This means eliminating everything that is not related to the problem.
You need (and this is by far more important) to, before sending the code, to test it at your site, and see that it behaves as you see at home. There are many examples that, when eliminated the unrelated code, don't show the commented behaviour.
...and then, without touching anymore the code, send it as is. Many times we see code that has been touched before sending, and the problem dissapeared.
If we need to build a program, we will probably do it with many other mistakes, but not yours, and this desvirtuates the purpose of this forum.
Finally, sorry for the flame.... but it is necessary to make people read the rules.
Well, I certainly should go to python since I did several functions of this type, keyboard event and mouse event, but decide to try to learn the windows api.
My goal is to know when button 1 of the mouse is pressed.
I created this file in a very beginner way, it returns in mouseData only 0.
The curious thing is that whenever I run it, it flashes my monitor at short intervals in blinks, but between 1 second with it off. Very strange that, execution is not viable.
Could someone help me understand and try to execute to see if it is only here.
Code:
int main()
{
DWORD mouseData = 0;
MOUSEINPUT tagMouse;
tagMouse.dx = 0;
tagMouse.dy = 0;
tagMouse.mouseData = mouseData;
tagMouse.dwFlags = MOUSEEVENTF_XDOWN;
tagMouse.dwExtraInfo = 0;
INPUT tagInput;
tagInput.type = INPUT_MOUSE;
tagInput.mi = tagMouse;
while (true) {
if (GetAsyncKeyState(VK_DELETE)) break;
SendInput(1, &tagInput, sizeof(INPUT));
printf("KEYWORD: %d\n", mouseData);
Sleep(500);
}
system("pause");
return 0;
}
I can reproduce your reported 'symptoms' - and the effect is really brutal!
Now, while I cannot offer a full explanation, I can offer a fix! You have an uninitialized field in your tagMouse structure (the time member, which is a time-stamp used by the system). Setting this to zero (which tells the system to generate its own time-stamp) fixes the problem. So, just add this line to your other initializer statements:
//...
tagMouse.dwExtraInfo = 0;
tagMouse.time = 0; // Adding this line fixes it!
//...
Note: I, too, would appreciate a fuller explanation; however, an uninitialized field, to me, smells like undefined behaviour! I have tried a variety of other values (i.e. not zero) for the time field but haven't yet found one that works.
The discussion here on devblogs may help. This quote seems relevant:
And who knows what sort of havoc that will create if a program checks
the timestamps and notices that they are either from the future or
have traveled back in time.
For the sake of learning, I am trying to correctly call the DirectX12 APIs using clang in pure c11. I managed to get everything to compile, but sometimes the vtable pointers seem to get corrupted and change where they point when they shouldn't be.
ID3D12DeviceVtbl* tbl; //tracking the vtable pointer for debugging purposes
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
if (D3D12CreateDevice(NULL, featureLevel, &IID_ID3D12Device, (void**)&g_pd3dDevice) != S_OK)
{
return false;
}
{
tbl = g_pd3dDevice->lpVtbl;
D3D12_DESCRIPTOR_HEAP_DESC desc ;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
desc.NumDescriptors = NUM_BACK_BUFFERS;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
// works fine
if (g_pd3dDevice->lpVtbl->CreateDescriptorHeap(g_pd3dDevice,&desc, &IID_ID3D12DescriptorHeap, (void**)&g_pd3dRtvDescHeap) != S_OK)
return false;
// works fine
SIZE_T rtvDescriptorSize = g_pd3dDevice->lpVtbl->GetDescriptorHandleIncrementSize(g_pd3dDevice,D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// works fine
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(g_pd3dRtvDescHeap);
// after the line above executes, g_pd3dDevice->lpVtbl now points to somewhere new and invalid
}
{
D3D12_DESCRIPTOR_HEAP_DESC desc ;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
desc.NumDescriptors = 1;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
// g_pd3dDevice->lpVtbl can't find CreateDescriptorHeap
if (g_pd3dDevice->lpVtbl->CreateDescriptorHeap(g_pd3dDevice,&desc, &IID_ID3D12DescriptorHeap, (void**)&g_pd3dSrvDescHeap) != S_OK)
{
return false;
}
// tbl->CreateDescriptorHeap is still a valid pointer however.
}
As explaining in the comments, after the line D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(g_pd3dRtvDescHeap); the g_pd3dDevice->lpVtbl pointer changes and points somewhere invalid and I don't understand why.
I am compiling with the following options:
clang.exe -std=c11 -pedantic-errors -g -D CINTERFACE .\main.c
You are hitting a known bug in the C-bindings... See this thread which explains there's a bug with GetCPUDescriptorHandleForHeapStart.
There were similar issues with the C-bindings with Direct3D9Ex. The basic issue is that almost all users use C++ for DirectX since it naturally maps to COM. The C bindings are mostly automatically generated; they are not well tested or maintained.
The problem
I am trying to get call ProcessOutput to get decoded data from my decoder and get the following error:
E_INVALIDARG One or more arguments are invalid.
What I have tried
As ProcessOutput has many arguments I have tried to pinpoint what the error might be. Documentation for ProcessOutput does not mention E_INVALIDARG. However, the documentation for MFT_OUTPUT_DATA_BUFFER, the datatype for one of the arguments, mentions in its Remarks section that:
Any other combinations are invalid and cause ProcessOutput to return E_INVALIDARG
What it talks about there is how the MFT_OUTPUT_DATA_BUFFER struct is setup. So an incorrectly setup MFT_OUTPUT_DATA_BUFFER might cause that error. I have however tried to set it up correctly.
By calling GetOutputStreamInfo I find that I need to allocate the sample sent to ProcessOutput which is what I do. I'm using pretty much the same method that worked for ProcessInput so I don't know what I am doing wrong here.
I have also tried to make sure that the other arguments, who logically should also be able to cause an E_INVALIDARG. They look good to me and I have not been able to find any other leads to which of my arguments to ProcessOutput might be invalid.
The code
I have tried to post only the relevant parts of the code below. I have removed or shortened many of the error checks for brevity. Note that I am using plain C.
"Prelude"
...
hr = pDecoder->lpVtbl->SetOutputType(pDecoder, dwOutputStreamID, pMediaOut, dwFlags);
...
// Send input to decoder
hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
if (FAILED(hr)) { /* did not fail */ }
So before the interesting code below I have successfully setup things (I hope) and sent them to ProcessInput which did not fail. I have 1 input stream and 1 output stream, AAC in, PCM out.
Code directly leading to the error
// Input has now been sent to the decoder
// To extract a sample from the decoder we need to create a strucure to hold the output
// First we ask the OutputStream for what type of output sample it will produce and who should allocate it
// Then we create both the sample in question (if we should allocate it that is) and the MFT_OUTPUT_DATA_BUFFER
// which holds the sample and some other information that the decoder will fill in.
#define SAMPLES_PER_BUFFER 1 // hardcoded here, should depend on GetStreamIDs results, which right now is 1
MFT_OUTPUT_DATA_BUFFER pOutputSamples[SAMPLES_PER_BUFFER];
DWORD *pdwStatus = NULL;
// There are different allocation models, find out which one is required here.
MFT_OUTPUT_STREAM_INFO streamInfo = { 0,0,0 };
MFT_OUTPUT_STREAM_INFO *pStreamInfo = &streamInfo;
hr = pDecoder->lpVtbl->GetOutputStreamInfo(pDecoder, dwOutputStreamID, pStreamInfo);
if (FAILED(hr)) { ... }
if (pStreamInfo->dwFlags == MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) { ... }
else if (pStreamInfo->dwFlags == MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES) { ... }
else {
// default, the client must allocate the output samples for the stream
IMFSample *pOutSample = NULL;
DWORD minimumSizeOfBuffer = pStreamInfo->cbSize;
IMFMediaBuffer *pBuffer = NULL;
// CreateMediaSample is explained further down.
hr = CreateMediaSample(minimumSizeOfBuffer, sampleDuration, &pBuffer, &pOutSample);
if (FAILED(hr)) {
BGLOG_ERROR("error");
}
pOutputSamples[0].pSample = pOutSample;
}
// since GetStreamIDs return E_NOTIMPL then dwStreamID does not matter
// but its recomended that it is set to the array index, 0 in this case.
// dwOutputStreamID will be 0 when E_NOTIMPL is returned by GetStremIDs
pOutputSamples[0].dwStreamID = dwOutputStreamID; // = 0
pOutputSamples[0].dwStatus = 0;
pOutputSamples[0].pEvents = NULL; // have tried init this myself, but MFT_OUTPUT_DATA_BUFFER documentation says not to.
hr = pDecoder->lpVtbl->ProcessOutput(pDecoder, dwFlags, outputStreamCount, pOutputSamples, pdwStatus);
if (FAILED(hr)) {
// here E_INVALIDARG is found.
}
CreateMediaSample that is used in the code is derived from an example from the official documentation but modified to call SetSampleDuration and SetSampleTime. I get the same error by not setting those two though so it should be something else causing the problem.
Some of the actual data that was sent to ProcessOutput
In case I might have missed something which is easy to see from the actual data:
hr = pDecoder->lpVtbl->ProcessOutput(
pDecoder, // my decoder
dwFlags, // 0
outputStreamCount, // 1 (from GetStreamCount)
pOutputSamples, // se comment below
pdwStatus // NULL
);
// pOutputSamples[0] holds this struct:
// dwStreamID = 0,
// pSample = SampleDefinedBelow
// dwStatus = 0,
// pEvents = NULL
// SampleDefinedBelow:
// time = 0
// duration = 0.9523..
// buffer = with max length set correctly
// attributes[] = NULL
Question
So anyone have any ideas on what I am doing wrong or how I could debug this further?
ProcessOutput needs a valid pointer as the last argument, so this does not work:
DWORD *pdwStatus = NULL;
pDecoder->lpVtbl->ProcessOutput(..., pdwStatus);
This is okay:
DWORD dwStatus;
pDecoder->lpVtbl->ProcessOutput(..., &dwStatus);
Regarding further E_FAIL - your findings above, in general, looks good. It is not that I see something obvious, and also the error code does not suggest that the problem is with MFT data flow. Perhaps it could be bad data or data not matching media types set.
Where is the implementation of the function dm_task_create in cryptsetup (and other dm_task_ related functions)? Grepping for this function in the source for cryptsetup I come up with nothing. I see it is used in lib/libdevmapper.c and that it has a function prototype in libdevmapper.h. However where is the implementation? As a side note, cryptsetup compiles fine and executes.
Just to check, I grepped through the kernel source as well but it doesn't appear to be implemented in the kernel either.
From the following link http://www.saout.de/pipermail/dm-crypt/2009-December/000464.html it appears that at least in the past it was implemented in libdevmapper.c.
It's implemented in libdm-common.c, which is part of libdm (lib device-mapper). It is not implemented as part of cryptsetup itself.
This code is maintained alongside LVM2, as documented on this page:
The userspace code (dmsetup and libdevmapper) is now maintained
alongside the LVM2 source available from
http://sources.redhat.com/lvm2/. To build / install it without LVM2
use 'make device-mapper' / 'make device-mapper_install'.
Here's the implementation:
struct dm_task *dm_task_create(int type)
{
struct dm_task *dmt = dm_zalloc(sizeof(*dmt));
if (!dmt) {
log_error("dm_task_create: malloc(%" PRIsize_t ") failed",
sizeof(*dmt));
return NULL;
}
if (!dm_check_version()) {
dm_free(dmt);
return_NULL;
}
dmt->type = type;
dmt->minor = -1;
dmt->major = -1;
dmt->allow_default_major_fallback = 1;
dmt->uid = DM_DEVICE_UID;
dmt->gid = DM_DEVICE_GID;
dmt->mode = DM_DEVICE_MODE;
dmt->no_open_count = 0;
dmt->read_ahead = DM_READ_AHEAD_AUTO;
dmt->read_ahead_flags = 0;
dmt->event_nr = 0;
dmt->cookie_set = 0;
dmt->query_inactive_table = 0;
dmt->new_uuid = 0;
dmt->secure_data = 0;
return dmt;
}