Taking a screenshot of the Windows desktop with a C program. - c

Is it possible to take a screenshot of the desktop and save it as .jpg,jpeg,...at any location in the computer by C programming? I am curious to know if there is any method and way to achieve this task. I'm using Windows XP.

Assuming Visual Studio:
This is copy & paste from working code (some lines ommited):
HDC hdcScreen = NULL;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
CImage myimage;
IStream* pIStream = NULL;
STATSTG stg;
HGLOBAL hGlobal = NULL;
HRESULT hResult = 0;
UINT nDataSize = 0;
do
{
//
// Get the screen capture in an HBITMAP.
// -------------------------------------
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = ::GetDC(NULL);
if ( hdcScreen == NULL )
{
SET_CHECKPOINT();
break;
}
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcScreen);
if ( hdcMemDC == NULL )
{
SET_CHECKPOINT();
break;
}
// Get the client area for size calculation
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcScreen, cx, cy);
if ( hbmScreen == NULL )
{
SET_CHECKPOINT();
break;
}
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC,hbmScreen);
// Bit block transfer into our compatible memory DC.
BitBlt(hdcMemDC, 0,0, cx, cy, hdcScreen, 0,0, SRCCOPY);
// Create a stream to have CImage write data to.
hResult = CreateStreamOnHGlobal(NULL, TRUE, &pIStream);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}
// Attach an ATL CImage to the hbitmap.
myimage.Attach(hbmScreen);
// Write data to stream.
hResult = myimage.Save(pIStream, Gdiplus::ImageFormatJPEG);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}
myimage.Detach();
// Get the stream's HGLOBAL.
hResult = GetHGlobalFromStream(pIStream, &hGlobal);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}
// Get a pointer to the data in the HGLOBAL.
char* pJPGData = (char*)GlobalLock(hGlobal);
pIStream->Stat(&stg, STATFLAG_NONAME);
nDataSize = (UINT)stg.cbSize.QuadPart;
// TODO: Open a file instead of a pipe...
//pJPGData points to the data, nDataSize is, well...
if ( WriteFile(hFile, pJPGData, nDataSize, &dwBytesWritten, NULL) == FALSE )
{
SET_CHECKPOINT();
break;
}
// TODO: Close the file.
}
while (0,0);
//
// Free resources.
// ---------------
if ( pIStream != NULL ) pIStream->Release();
//Clean up
if ( hbmScreen ) DeleteObject(hbmScreen);
if ( hdcMemDC ) DeleteObject(hdcMemDC);
if ( hdcScreen ) ::ReleaseDC(NULL,hdcScreen);

Related

GetOutputStatus says output is ready, ProcessOutput says NEED_MORE_INPUT

I am getting stuck in this situation where I get conflicting information:
hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
if (FAILED(hr) ... )
//ProcessInput went well, no warnings from here.
hr = pDecoder->lpVtbl->GetOutputStatus(pDecoder, &dwFlags);
if (SUCCEEDED(hr)) {
if (dwFlags == MFT_OUTPUT_STATUS_SAMPLE_READY) {
// I get to here, sample is ready, yay!
}
}
dwFlags = 0;
hr = pDecoder->lpVtbl->GetInputStatus(pDecoder, 0, &dwFlags);
if (SUCCEEDED(hr)) {
if (dwFlags == MFT_INPUT_STATUS_ACCEPT_DATA) {
//...
} else {
// we go here, input does not accept more data it seems.
// Sounds ok, we read the output that is ready and then we fill in more
}
}
dwFlags = 0;
hr = pDecoder->lpVtbl->ProcessOutput(pDecoder,
dwFlags,
1,
pOutputSamples,
&pdwStatus
);
if (FAILED(hr)) {
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
// Ok, but why did GetOutputStatus say we were ready then?
}
}
// Calling GetOutputStatus to see whats going on
hr = pDecoder->lpVtbl->GetOutputStatus(pDecoder, &dwFlags);
if (SUCCEEDED(hr)) {
if (dwFlags == MFT_OUTPUT_STATUS_SAMPLE_READY) {
// nope.
} else {
// Now dwFlags is 0.
}
}
hr = pDecoder->lpVtbl->GetInputStatus(pDecoder, 0, &dwFlags);
if (SUCCEEDED(hr)) {
if (dwFlags == MFT_INPUT_STATUS_ACCEPT_DATA) {
// this time we go here, we can now give more input again.
// but we got no data from ProcessOutput
} else {
//...
}
}
dwFlags = 0;
Looking at the data media sample I've sent to processOutput to be filled in it simply writes a null terminator '\0' in the beginning of the buffer but otherwise it does not write any output.
GetOutputStatus
If the method returns the MFT_OUTPUT_STATUS_SAMPLE_READY flag, it
means you can generate one or more output samples by calling
IMFTransform::ProcessOutput.
...
After the client has set valid media
types on all of the streams, the MFT should always be in one of two
states: Able to accept more input, or able to produce more output.
I got no errors earlier while setting up the decoders input and output streams so Im thinking the streams should be good. And I've not got any warnings while sending in the input media either so Im thinking I should be in a valid state. But the behaviour does not seem to match what I think the documentation is suggesting. Also I only have 1 input and 1 output stream if that is of interest.
So how could this happen? I have conflicting information from the tool. Is the data ready but I am reading it wrong, or is there something else going on?
Edit:
There were a few comments asking for more information, and one asking for a minimum complete example so I decided to try it out. Below is a small c program that runs all the things I run and it simulates my environment by reading input from a file and sending it in the same way I am getting my data. I have striped out almost all error handling, removed helper functions and hardcoded a few things. This program reproduces the issue. I am running this in Visual Studio 2015.
#include <stdlib.h>
//windows media foundation test
#include <windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <stdio.h>
#include <mferror.h>
int chunk_handler(unsigned char* pBuf, unsigned short length);
IMFTransform *pDecoder = NULL;
DWORD dwInputStreamID;
DWORD dwOutputStreamID;
// inspierd by FindDecoder here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms701774(v=vs.85).aspx
HRESULT FindDecoder(
IMFTransform **ppDecoder // Receives a pointer to the decoder.
)
{
HRESULT hr = S_OK;
UINT32 count = 0;
IMFActivate **ppActivate = NULL;
MFT_REGISTER_TYPE_INFO inputType = { 0 };
inputType.guidMajorType = MFMediaType_Audio;
inputType.guidSubtype = MFAudioFormat_AAC;
hr = MFTEnumEx(
MFT_CATEGORY_AUDIO_DECODER,
MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTER,
&inputType, // Input type
NULL, // Output type
&ppActivate,
&count
);
if (SUCCEEDED(hr) && count == 0)
{
hr = MF_E_TOPO_CODEC_NOT_FOUND;
}
// Create the first decoder in the list.
if (SUCCEEDED(hr))
{
hr = ppActivate[0]->lpVtbl->ActivateObject(ppActivate[0], &IID_IMFTransform, (IUnknown**)ppDecoder);
}
for (UINT32 i = 0; i < count; i++)
{
ppActivate[i]->lpVtbl->Release(ppActivate[i]);
}
CoTaskMemFree(ppActivate);
return hr;
}
int main()
{
UINT32 samplesPerSec = 44100;
UINT32 bitsPerSample = 16;
UINT32 cChannels = 2;
HRESULT hr = S_OK;
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
DWORD dwFlags = MFSTARTUP_FULL;
hr = MFStartup(MF_VERSION, dwFlags);
// Create decoder
pDecoder = NULL;
hr = FindDecoder(&pDecoder);
// Create input and output audio types
IMFMediaType *pMediaIn = NULL; // Pointer to an encoded audio type.
IMFMediaType *pMediaOut = NULL; // Receives a matching PCM audio type.
/* Create pMediaIn */
// Calculate derived values.
UINT32 blockAlign = cChannels * (bitsPerSample / 8);
UINT32 bytesPerSecond = blockAlign * samplesPerSec;
// Create the empty media type.
hr = MFCreateMediaType(&pMediaIn);
// Set attributes on the type.
hr = pMediaIn->lpVtbl->SetGUID(pMediaIn, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
hr = pMediaIn->lpVtbl->SetGUID(pMediaIn, &MF_MT_SUBTYPE, &MFAudioFormat_AAC);
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, 0x2a); // value can be found in my onenote, (AAC Profile, Level 4)
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AAC_PAYLOAD_TYPE, 3); // (LOAS/LATM)
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_NUM_CHANNELS, cChannels);
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSec);
// blockAlign, bytesPerSecond and independent samples were commented out previously
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign);
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond);
hr = pMediaIn->lpVtbl->SetUINT32(pMediaIn, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
//first 12 bytes:
//wPayloadType  = 0 (raw AAC)
//wAudioProfileLevelIndication  = 0x29 (AAC Profile, Level 2)
//wStructType  = 0
// The last two bytes of MF_MT_USER_DATA contain the value of AudioSpecificConfig(), as defined by MPEG - 4.
// 00010 0100 0010 000
//AudioSpecificConfig.audioObjectType = 2 (AAC LC) (5 bits)
//AudioSpecificConfig.samplingFrequencyIndex = 4 (4 bits) (44100hz)
//AudioSpecificConfig.channelConfiguration = 2 (4 bits)
//GASpecificConfig.frameLengthFlag = 0 (1 bit)
//GASpecificConfig.dependsOnCoreCoder = 0 (1 bit)
//GASpecificConfig.extensionFlag = 0 (1 bit)
UINT8 audioSpecificConfig[] = { 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x10 };
hr = pMediaIn->lpVtbl->SetBlob(pMediaIn, &MF_MT_USER_DATA, audioSpecificConfig, 14);
/* Create pMediaOut */
// Create the empty media type.
hr = MFCreateMediaType(&pMediaOut);
// Set attributes on the type.
hr = pMediaOut->lpVtbl->SetGUID(pMediaOut, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
hr = pMediaOut->lpVtbl->SetGUID(pMediaOut, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_NUM_CHANNELS, cChannels);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_SAMPLES_PER_SECOND, samplesPerSec);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_BLOCK_ALIGNMENT, blockAlign);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, bytesPerSecond);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample);
hr = pMediaOut->lpVtbl->SetUINT32(pMediaOut, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
// Figure out streamcounts and ID's
DWORD inputStreamCount = 0;
DWORD outputStreamCount = 0;
hr = pDecoder->lpVtbl->GetStreamCount(pDecoder, &inputStreamCount, &outputStreamCount); // both StreamCounts == 1
DWORD dwInputID[1] = { 0 }; //hardcoded
DWORD dwOutputID[1] = { 0 }; //hardcoded
hr = pDecoder->lpVtbl->GetStreamIDs(pDecoder, inputStreamCount, dwInputID, outputStreamCount, dwOutputID);
if (FAILED(hr)) {
if (hr == E_NOTIMPL) {
// This is expected and quite ok.
}
}
dwInputStreamID = dwInputID[0];
dwOutputStreamID = dwOutputID[0];
// configure decoder for the two audio types
hr = pDecoder->lpVtbl->SetInputType(pDecoder, dwInputStreamID, pMediaIn, 0);
dwFlags = 0;
hr = pDecoder->lpVtbl->SetOutputType(pDecoder, dwOutputStreamID, pMediaOut, dwFlags);
/*one time setup is now done.*/
// simulate sending in the first couple of chunks that I can get while trying to decode audio
// Reading this from file, again this is just read from a file in this example, in my real application I get the data sent to me in audio frame chunks.
// For example the first "chunk" of data is:
// 47fc 0000 b090 8003 0020 2066 0001 9800 0de1 2000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 001c
errno_t err;
FILE *file = NULL;
fopen_s(&file, "input.txt", "rb");
unsigned char line[10000]; //big enough
#define NR_OF_INPUTS 14
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
int sizes[NR_OF_INPUTS] = { 42, 42, 42, 42, 42, 340, 708, 503, 477, 493, 499, 448, 640, 511}; // lengths of the data
int i, j;
for (i = 0; i < NR_OF_INPUTS; i++) {
fread(line, sizeof(char), sizes[i], file);
printf("Input chunk number: %d\n", i);
for (j = 0; j < sizes[i]; j++) {
printf(" %02x", line[j]);
}
printf("\n\n");
chunk_handler(line, sizes[i]);
}
fclose(file);
return 0;
}
int chunk_handler(unsigned char* pBuf, unsigned short length) {
const UINT SamplesPerSecond = 44100;
const UINT ChannelCount = 2;
const UINT SampleCount = length * ChannelCount;
const UINT BitsPerSample = 16;
const UINT BufferLength = BitsPerSample / 8 * ChannelCount * length;
const LONGLONG sampleDuration = (long long)length * (long long)10000000 / SamplesPerSecond; // in hns (hecto nano second?) 0.000 000 1. (Duration of the sample, in 100-nanosecond units., see IMFSample)
HRESULT hr = S_OK;
DWORD dwFlags = 0;
/* Setup for processInput */
IMFSample *pSample = NULL;
IMFMediaBuffer *pInputBuffer = NULL;
hr = MFCreateMemoryBuffer(
length, // Amount of memory to allocate, in bytes.
&pInputBuffer
);
BYTE *pData = NULL;
hr = pInputBuffer->lpVtbl->Lock(pInputBuffer, &pData, NULL, NULL);
memcpy_s(pData, length, pBuf, length);
hr = pInputBuffer->lpVtbl->SetCurrentLength(pInputBuffer, length);
hr = pInputBuffer->lpVtbl->Unlock(pInputBuffer);
hr = MFCreateSample(&pSample);
hr = pSample->lpVtbl->AddBuffer(pSample, pInputBuffer);
//hr = pSample->lpVtbl->SetUINT32(pSample, &MFSampleExtension_Discontinuity, TRUE);
/* Setup for processOutput */
#define SAMPLES_PER_BUFFER 1
MFT_OUTPUT_DATA_BUFFER pOutputSamples[SAMPLES_PER_BUFFER];
MFT_OUTPUT_STREAM_INFO streamInfo = { 0,0,0 };
MFT_OUTPUT_STREAM_INFO *pStreamInfo = &streamInfo;
DWORD pdwStatus = 0;
hr = pDecoder->lpVtbl->GetOutputStreamInfo(pDecoder, dwOutputStreamID, pStreamInfo);
IMFSample *pOutSample = NULL;
DWORD minimumSizeOfBuffer = pStreamInfo->cbSize;
IMFMediaBuffer *pOutputBuffer = NULL;
// code checking for if MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLE and such, Turns out client (me) ne4ed to provide sample so lets do that
// Create the media buffer.
hr = MFCreateMemoryBuffer(
minimumSizeOfBuffer, // Amount of memory to allocate, in bytes.
&pOutputBuffer
);
hr = MFCreateSample(&pOutSample);
hr = pOutSample->lpVtbl->AddBuffer(pOutSample, pOutputBuffer);
pOutputSamples[0].pSample = pOutSample;
pOutputSamples[0].dwStreamID = dwOutputStreamID;
pOutputSamples[0].dwStatus = 0;
pOutputSamples[0].pEvents = NULL;
//INPUT
hr = pDecoder->lpVtbl->ProcessInput(pDecoder, dwInputStreamID, pSample, dwFlags);
if (FAILED(hr)) {
if (hr == MF_E_NOTACCEPTING) {
printf("Input cannot take more data\n");
}
printf("error in ProcessInput\n");
}
//OUTPUT
hr = pDecoder->lpVtbl->ProcessOutput(pDecoder,
dwFlags,
SAMPLES_PER_BUFFER,
pOutputSamples,
&pdwStatus
);
if (FAILED(hr)) {
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
// this is ok, just need to make more calls to ProcessInput
printf("ProcessOutput needs more input\n");
}
else {
printf("error in ProcessOutput\n");
}
}
return 0;
}
The "file.txt" references in the code should contain the following inserted as hex:
47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066000198000DE120000000000000000000000000000000000000000000001C47FC0000B090800300202066200198800DE120000000000000000000000000000000000000000000001C47FC0000B090800300FF4A214DE73987D722230566AD966E80B72A99797BFFB7978EB3DB9E248875BA38E42B7924EF58A2CCC578931AE67157BF6E7E3DC51B70265C888DA8CB0074753F9F0F3EF9B0F70CD8D5B2363C3B9CE1275DE0E4E7313C6F88FC611D87A932D4263BDFB8C74B5E9052DD5046AF66EA3AB55F9E2186ABCC5A72A3664F1CA21CC678AC24CBECD3797D7C2C50B335556E7DF5E51E5BECBEA1337CA71ACB7ACFD9EDABE47139CB0695F8D575EAB0E461BB5336ED00E2F0F5F381CAD2E9E2C0750FAE43460E9B372CCD016EE6E5547FF4F89EBACF3BE2EA21D7E9038E190CA4D46DB54633FCB9331E830DC6AFB7A1325F0E79DD1C6D886320F8C728DAA34AD00CA999CC089702E7CD7FD8EDEB1FEFFAB63F8D9E798CD483BE697B314BF749F17967FE9F46688D45D8D6B926300840223B9AD2B7291B288518835BB2629B61D79EAB5760D16FBEA3B909D4E7F56747FC0000B090800300FFFFB4216BD505EE8504B0D098342810840D0AF6CCCD71DEADAD6EB2F7117B85CAE255CC5C39130EF0EA7A7F7565275CB6CCBB9E70843BA4847444976535677F95480D0AEC0D0A63F40F1BF7B645AB70307D0262A388BBB2DE0F90E12FF5B46A2EAEB1C8E85C50061833EF9324731B4F7D29580BE0FA0DFAB6AA78341FF25422B0A7039F64C34BA063763E54D489805ADE242371C3C865F17360ADFD3956E6A6AC18D8463879AC4FA70D0ADAC9C5E146F5BB6541F8ACB2EEA53D1EF35EB0ED715F7C4B9A1A072908A66CE92A76328E43010B3820EC9E255C388BC5DE3E02D1393EA9FC70CD44555DE9F6E419C20F804F0361AC702CFFBDD6DEC4BBF6C7736AA1F207CFFC9934E9DBF039FE469D1B2B50B4507E8F6326BA9BD42B71A1A7AE74D23FF1F89CDAF27D614D3C2F8AD767004AC2421E11D8B86B058DEF88EB9A9C8E8C35CF980D0A56664CF27385181987F7878D06AB6F7E46200764841CB0820195C383613579C8836BA8622C06DF3889D200773EDC28AF89E3656DEE0699E66DDB9E7070EFB96BB024F2B4155A9E7806649A8C00A383586956581A0602015141282C140B100CF358BE372EEF5B65E51ACDEB2EDC4A9ADAD00D10420408761E859304BCD8828E72EEEC4AD4219560E77946692F3C51EA9BE12AC6431DFF674CF94931D357B6EF90E912A3B9ED135C6D620EBF7D887A38CC78E67B543838ABA936E67848A2744AF716CB8955C1CE9FB4784271584E49DE019496B654C6B413D74AA09ACFDF68233F39F176931E10A093B0C47961BC72F87C31FC3EA92BF55438EB90345122D1DE3BA14653C459A53C0E5CA3D8ED1097DDD3D5DB39C645D5E07396C76131C03B329A3C98E65A19E63380B51105F21089088038309AE0E4A17C6D6D827D5D85FF804805BAFC4441580F7FE5872EC3DD9C9C00312022F67A4D40AF900D0A1A5427DA204E113C93931E9A0209F7CD2303102E9F674A3B2B706E47FC0000B090800300FFEA210BD5159E8F6982B1602C703386BC713BE1AA54E75B0BA9092E29726E03838C74AADE6D55F03227C9F0F84F90159F2C64D517A77D6F1D69258146F8A3397C3BBA296084B027A9E6581390F1A00E4A3A26E67944B2F09DDEF851344D3BF2DA8A8B11C1C00750A7B34A310D04481F02AE190D0A41F83BD088CE2ED2BE9FE1819099C7A22D5C6738C32DE20F2201D6A603A2082DA21D6A677E2E471044B72C64C6085C734BD1C8D9E1287E93A588C4BAFB075E0D0A3751BC5ED4009F7F7E2500A8394D0B3D0D0A18F9CA85996BB1651362C72A739DE23A9ECDCF6CE771C523B42CB0A698213E554967559681AB800574D36050440CA4D00E48AA71748E65F5CAF6BAF7B01A64803C453ED2093582B6236DDE26AB2B2BC500002A129D1A56FA19400000E22952C4AE3BA298876484D89D4A832819C4D733AF5E6BADCACAE37CA17624B936E2A77A0914FB393C13DB11C2EF9C7E039F0718E7FFA578FDD875ADE3B4F3FAB20CF08AC721C4182E60E5A2D4DBCDA1810F88D64ADDA7CAD3981ABD3AD8E114BD505EBD8D5D7CBC9967899697B38D411ABAE11B391718EE9BCFAB917196FCC2B910B9170351CBAEB97577CD6F1D3215B0E72EAC739176AEAD6009AEBF56B882BE32319DFDFD33D5F28BA0706BA273601740829B8BADCE4537BD6BEF9BE0F9D2CBE60884F9225109718E47FC0000B090800300FFCF210BD51DB18561A4C0D9683033CD5F8EB5EB55ABDC64ADD244B26A26489960D9D84969A878658210307F2D01CE29359116C0739E92EA87B35B0D0AD5F223F143BE0D5D6EB2B69CCACFDECB8C36B5D9B771E03295998B9A62498D887106EC5E918E0C30076F5ECE6403391363A62CB44CBB6EFFD74CAC0CF90D0A2ADDC490E2306145701D85B1A9CA12C258CB7D81532D99FA8DF3C7A1894357950D0A0C0B7CBDB8D297200CFAAD4AEBC92BBDEE087AA9BFF6A49C2B7A7BC66900EBD78F859330033EB9C009C649B8A0E99E774E3ACC0C01DED63CC2247BB5A3C857D2D50D73D92C5BD345ECB6E9A6FEC7000D0AC2F870CEA2AB20BE4057C9EF9922083AA2ED64350DB514A84A0405E3CE51B6FAE53316CBFA2C87B393C5CDAEFB9561FB12DEC4C75F3C69C876464D094EC255825E57DF5AED77158BAEE979A9AA4BBCE372507AA149F8A2108A682471F2BD48D3DDDA49E896AFEA79BBCBCB96E00759FB9E77B110866D32F8C3061C4655E056BF8FD5F0417D1BF296F735F0D682437F67D9BCC05D6E8BD6E725050C41133E9D9D3E76280444FC260D435C631302720B6EA53BE9E7B890405D4564310F7F2C48027535A15DF807777F1EEF7F57DC0BDBBB398004C1CC5D159991BDAB0373926719A000006A1C47FC0000B090800300FFDE210BD515B290C2A0C1944C741819E4E755755C632A537335ADAD2EF5544B5481F1B472C55D552D4982F5FF89A5E18B3853B70D0A6380EF43AED06FBE5510F067C8E66CC6E0568C614076560EDDA09A3150EC4091D6FFEC2D78A38EF6FD5D52D0DC9F2BD2F3DC2DF9FA413F130355403920A91E9D2FA1FBAF09A7C239059DF6D3A72B24E8B96340288C68DEB4D9D44E9D2DAB0D3F8BBF15CDA44D549DCF8345F55DC594A21615BD6128E17D700240980B9DE7FC2456E7B7D5A0999AAD8EEEFF8B970E78B5BC34559F98FBA90D9C28BE444F0D0A8DEC59EB7D38104926B66CAC98E8B6DD3E69A2BA899B77D4C002DAC600A5734B62A006A1886E511063F09E93ADF3800B8E1CEBC528B8630900AE86759E7D1F08DF9DE47E57E93EC05714FDAAC43FCF03E57A551D29094162A8506AA31021E738E784DB8DDF350E667536B3875554BD5609E7C846792B5B0D0AA9DCCACFB143A6AB0B087917695136C22505859DDFB9E2CF3FC73FBDBEE77C1E853B74A0C023755C2BBA329D4C1D0298AC33342083E328F7F6663D5403C12943925C1007AAD0789F0E429D909DE53DA00D0ADEE57C77A966388A04C096FE3D08E41189037D5C2F32D71C015B46F31DF3F1D6855556F7A9339D0D0ADB788178227218CEB505E03BB5C7EEAD6A0BC63CFF7E9F4F00DD1C47FC0000B090800300FFE6210BD50D9E936181B0A0AC270B1102C451019A943352D95553994D5EEEEA5EB55448342299BD823F916D8AE11EB398B2D5CEB34CFAD3B2818D3F9E30884B0D0AEC3A05147354117537040109F46A27CD52806C4279C1C3E9FD9F6620C3ABF2AD8702767FBE226C934BDCD0E2BBD40E4003136CB1A3CCFD951FB2D8E9DE5415B55384B798B48C32469B56B54506917A7627332D8C4FD7A85897697186EBFCEBBE26D3C6D94D107198D32BAC82FCD0B081BFF7B43C4D8CF9786BE3221B39DB69080052494AF6E6A310BB6D8A50A45AD99DC00D0AAD604E4169612A8E75F96CB437EBE93645816D58F03BF46FEA654056FBABAE703A4899000C90F7F748200D39BD4FF897B19092B0BA000066B80E8357461289899CAF12055C66FEBE9E118E572C4494A438208A0F45632A1022503349AC6F8BE32B19399249BBBA4EB46DAA258D847BADAF69EADE38B19AA09DBD707825ABFE12D1E74C88B545354477A140A7CF3E83A47350CCA0796ED91F102C2378BD91B2A8820D9C0430C8096CC6C007279AF9984B6EAAC420D41DC51656027437981BC26ADA054E2EC7F2E24AF461733B014002A18EEFB2635C38700D0A89F872EACE26AF3B019F86B15383BFC72075F52EBE1F0CE3BFF5E3AE75AE38C4CA402304400714037E466C2802534AF14B0600101370D000705BE2E047FC0000B090800300FFB6212BD4ED9E936182D0A08CB04353DEC47192B753BE0975256A5945A507ED211FBFABFBDFD8B7E5E14B401438D2ED27B9D8E7E30651A8224007FF029525ACBEC13E7B2D6503DC54CAA43A1E35D7D264D0DB50F3789F04142A8902C1D6E0ED0080C561CD098EA1EDED08A04A8EBA2993001374E57D54528315752B83C7116C3725458CB05078123B8D8F3CB6E0976FB8F0A914A051B66CE31EDF5153AD9A011948859002F1A81CA6529E33155B64EAE03D2599AB5A501F05A72EAB90002CC2FA2BAE2E929CC7659A8099E80D6B9E79CA3C6E40B8FC25B18C6D689E819DBB335A7405E539405ECEAA41395B6D315146F14C910D40EC95B768B86204D44640B5A806AAF52AC2DDD423CC4B4E108F5844E6235D051E16A18131548023200C44065F1F6B5E5DEB2F2B75BD5D59755ABBA55CB04027445D19A4858A1C48F732E11169DB549AEC4BE6E3910C01EB3DBF85B3585D7E4DCAD92DFBBCEF54298CE02321D79BA0DAB0010D88105387DFFF664000066AC6CCFABF22F7401899A064D249404E84C90B989B5405C6FB534842FA37DAAE4679C9B902EBA4675EEE5DADF46E00251781D8F6DC5D6BCE23F1FC2194128B1316D08805038047FC0000B090800300FFFF72214DDEFFFFFF3336A9B1A2D1C81B54A1DA62A80B8F112FA2FF1FF13779A9C4DDF41DBF58B878CF6840F504F3FED85D1608DE4BDA7D0748C2711E387AFD2C656A7C078531B2A9B2D5A7F07E8671F9E7E41B3ED4F031EE923A47C8FF0D0A94305B24B1CEEA67EC5A3A74EA9B6F7285B3C68E0FB587FE1A30DBFBD5170532508F2D095022535C81BAF3C8068A2E476984FA49121FB15851DE70AA3EDAC7A4F285AC068F1F39BC124BAB7BCBEDB59A0D0A7EAB05AEE759E63F48C64EEAB770833C3352FBCE1E417534B457F411155A5694BBA5D190B8C934CE6B5DF88DAB9777303994614BDDA9A50CBC15E0AFEC1F3DA00DEBBC25304658E57ACDCCFE743CCF2D97096C43ABBA3EFDA47676B38B3C7E308D54B45A3B8D8470BF98EFCED3C9D5A375EE4566E39C6807A0072BA6F9F19E8B25EFEA994AFFE67886B80DAFE0FBF9A26768E3D4EA63974BA55CB83B15CBBDD95E3D3007C2009000009AA31113136E40D46506CD162A80AF9893DB1AFDFFECABE78BE1BB807B20B5E81EF71CC44F05FBA36F78B60957374E4DA34C8A7A9236A3EF391BC15CD9ED7957AB2422E89444BCBAE7B93F9D6E23D8FA2DDEE93FAE64FB7FB824389C1F8096FA407C88C3081FE7CB3FEBCE03728C752131676EA6B105B4681D75368D4F245EE81EACF386076278C95924087B56FC0E2AD55F77A6A44B28A9B25AF286BEBD27226A18C2E2BA296FD959452A32E9231ACF2CEE5C050478175B83696AFAE0118C5984F3F724A329DCE25230C9ABA45FA9EADB6E64C57E9609F22B4D3E8651E60DDF127A6010A3320BA3D0BFA22D921572043923A011330D0A003A5A67F67D3F2FB39FFDFF0D0ACF6763F88F838C001F3CFD9D523FCDFB3B02F19000007047FC0000B090800300FFF2216BD4FDBE8D0E620840EC8BC78BDFD139EED7968BC6B495922D9438B20F89CE72499D90F50FD31ABA4B912523B81ABD5BC3F1AE5F9FF34E75F97E68E4876E1AE381C96FE987C9F366AB724F3C634CA9AA4A1E27758C5D5EA32DF47634CE4B8EAC1DA6522172C6BEF6B78B6C21A968325B87FA4B8C75DFC9AF7E3AD024A6D45DF651B19D99133869232C0CA24BEF0DA6CA2133CC0277D02C0FBD2104C9A58C22A45E6E0520C1A55DEE48AA9B600D0AEA6BEE37AE66ACB8DDE4E53C23D36D4448C397749D19F2B1E68428D0A7C57EB91A4860B12C4D69769DF1D4C69CD4D04F9D72934AB58E51072C4B09925BD7DA02259693C4C0FC25218F6A78216AA094DB7AA3619D6F9E696E7B25510006A6DC24FD5BDB1348F57C63CAB3DF759729524CEF7E40014C5637D7AE61000322198D20A41142EC4C45431504650433AAD667339FAB5F7DC6B22D2AB8D456EEA5B63493B898F6DF0F70DD916C86A6D462BB14C15C776CF8EDA49868E510773CC69988D806E1870859E0B344AB8F1B6C3BFE417BF7E9884F2128F5F4DC3B63E1238E6312D76F2E8E576057340BD2E2A4ADD6484457609AA80209CD4DBE126F9A509DD011A9FA7DBD617DCF84B948BB7B616CEFDBE094B829D525FBCA7B2582A52421BAA94AC8A8A667836D98C5D5711A92FFE8B8F97433278764D5D5D597F7BE5013C0CD605C1C47FC0000B090800300FFC2210BD50DBA0D618431602A200B04C40656A92FD4DF152AAAEB591245A242AAED06E8F0672C5946157169B9AB6ACB4F1866BA4137814BE13F05A2411098969DCFF61E40B4BE944463971C375920B2BEBF3A52F0E2D1869C9A888FA900465D2C74FC76F45CA4CE0D0A140D0A695E04899CC9250D0A8F80C42290A86140C5B248EC8EB7392B6E14215BF0C9CA0341490623A1391B0D914C92E7395009A2E15134A7125C2557891339CE05826194D5D4EDAC6B192FF34B8600071E6E14E38CD3852EEEB194F2D963C817DF43D0C0E0FA9128E525AF7A10B9257719C014437538E585FC4A8F51E58128CCBE659EF01E420D0A1A6AFDDE784FA351F1AFD5009DF4FB669871E7BA8C8A2CD84E5DC355583B2A7A9F0FD2DE041D1BA072F00292D30563A2D4802108215EDB8E3F4D6F52AEB76D622D5A45CBCCAE01AC8707447199D2B8193647757C0014E4BC4E8DD9D251E0755086332FE1E122E318533919E1171A85F17DEC4B7F30EA40005ECF1322EF9705A2DADB354EF0D71653C09BA5771CF866F6B4692BFB53A20D0A36ED3BD63B5397E1AB1C76A6066610535CEC5857AA165F8A3BDE3AFE62C14540A8AFF1CAFD7351D7638E0D0AFE577D1B1753015C98CF3AD1588056C07EF11C47FC0000B090800300FFFF14210BD51DD612C2A238A04A1032F86DAF9E39F6BEEF61256A2492AE5A492E507266D8A485B1C91050CF618CD9D24CE9422880B92E969794BD6EE21043A9B997E8E5D02CAD01D5EDFCD8B871220B37D4CE28394314B723411472F6DA23E15CA10D66D7147D38C0B31AF672573349490915B6D97078FB5216D535437AFA64A678C4507414C17AE5E54217F0928AE120AA4785CF3F2AFE23CE722FEC6DAF8231ECE7B282285F116A70137C711FA2C90995AE22233874438CA69F0827AC2318B4DB7DD3825F4DCD72EFCA13BEECA7B33B500C24F86B032995348674CDE93D20D28DC69B44836A2268C6383600AD36D5EC1C7BEC2C0513E4629551BA966ADF93A8F5685BEEAF417384CBA8556AA4C9C797361D1FF6F65CAF91AA2A7180000D0AECFCF8A27CB9FCBB33CA6E75A45F9A5D5566D68ED32A7169E09938465DC13D5FF9F6F1C635A8AF3F648535B98D4154A08C4C15080982A2032FE3337AED5ED399CD5E5D719A8BAB9BE2173A6034F9A257E49449860F1F3234D1E7A7C1FA3154C6FC7C53088642EC3B6454AAE6AFB85BA6A3437CBE2624C9CDC9D46A9C00CAC1300557BF14621033ED6CCE4F846AB973EBF9F216D31DFC2A6205E3B65BF0EC84AFBF58E701778C6E78EF8004EE98EBEF8ADEFF856C00089D7AAD2B65E220AFE016A1473108E0CE9461F75AEAE24B9753B810A8C348A9870D7373F8FB3AFEE07C3521BFCCF7E51132B76548165BFAB62A73300FBF40003847FC0000B090800300FFFF1F210BD51DC6890761C0E84A281819D5E7377DB9F3795855CBA5DDB24BB9217C503B377F9A2BEC89E1CFC791C41158ED857519F6B98E872BBEA9B614500C6FCF7E468CB64F31AE089CDE696E45B29D9F3874F083E36F6AA0CA5F849622858B8F4153CB0721ABACB0FCF4B0A209E092CB70A10D0AC689F786783E85E022E8E02D4CC2AC1AE0984E701926788007936A163026CEC02DA74C159B3AB81003236120A2630E9E85980966AF95D712FAEBCA35EF9F4918972FF646A17B757FB28F2A67007C26B281C925832AE31703971AC6C931F10CD6DACABB61D49A8BF071B4947D952A33789A89A54C5757C1DF155B58C62BE42982A928E8ACE39C75DA8B0D2F0B518C7D975D846EC28236543C505AFB3D7ECA81A80000673F2EBE8DECEDFDFACAD8AB7AE33B43B2F05E722499D77A4D223A2DF7DC42437AC0B03D271F05379CE739CEA7B4B1A82C210D894C8452889828103BDB59BBBEF3BF699372A389556E1BB6AE495E3DBCE02863569A20106734826201CEDD6DBF328E8EA8E13833AFA5CE678A43ECACAE056F438204DE3F666ACC594CF22AC0A0238671CB13CA31BBEF5D1E38EC8CEFA372BA8EF29CB1EA825590EEC95BE0AB98BC4DFBFA60C7DFD18CA5FD6F1D94832B9D4A2F46EB40E777B2C321FC8BE45BBD477B3BFE94D7BFABB61DDDE62B2F679F007BB8ED7ACFD9D5C7D935F1E9E3FE9F1800AFEDF1FFAFE5F672FF3DE2FE50E7B83AFA400004B8275F20987F35768CCDAEE5D92358534EF57847FC0000B090800300FFE9210BD525A68D6181D098B4180B0E02C451308C20679BA6FCFBD73E655EF6B8B2692A4B092F554152C8CC9205E29FA1F9D772C440C559DA53E5DFD1398ACB4BE64512620F63F0F92B20EEC15947AB0E2032125AE3D054070D0A7FF21BED4335F82519E41E12FF8F0051C5B625EFCA1005A8AEBEFF8DE407E4DB9655E7ECB95ED8C7CB496524916480007916D9278CC3EBC697721DFF0D0869C9A008D1326C2993079D09DCB1D3D0AB84EF3ED249260EDBB1F2C37F7F6D7A3BBB6E69EF7291A667BAAAD6B918D4A92544E23A89B38AA35E781A4BEA47FAEFD482A873DD4D7CE903BB5C9B7826170537DD2C9D293450B2E49701CCE49E9CFE1DDF8D98C4700B9808559CD6F7BE9E000D01A4B1F4FA8B8787C3FCF282FAD6CCDC960542EB9CF77D5D75DC63F7AF27A51920A741D9A156250D0A115402408880CEA5CBBF9DEFCDE71CF3347189C52AEB8CB2BE302116B6FAA464C548A09BF3AC27F9AC0093C55F0004D671C4A53924BB758CF48C9F302A31E1B0E340339630896052D4E6D2C418E38203E952003C4B7F9635A743DE4D2C284D206EA7E25CEB9AAAD095F1306F11D7F2FE5323ABBE05EFBE031D2D467BF711A847074702B60B910C639FB30BC600066000DF8F6856EEE57D3C2B35BDCEBBFAD20365E9598E8854AB6361A0790B5FE6DB3F2DA27493AE106C01C0
The input file is also here:
http://filebin.ca/3DACc6lkf882/input.txt
Edit 2:
Here is a sample from the MFTrace with some extra traces put in there:
23816,3D70 10:43:31.09829 CKernel32ExportDetours::OutputDebugStringA # ----------------------------------ProcessInput----------------------------------
23816,3D70 10:43:31.09832 CMFTransformDetours::ProcessInput #00000229F1932698 Stream ID 0, Sample #00000229F19D2160, Time 0ms, Duration 0ms, Buffers 1, Size 640B,
23816,3D70 10:43:31.09832 CMFTransformDetours::ProcessMessage #00000229F1932698 Message type=0x10000000 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, param=00000000
23816,3D70 10:43:31.09832 CKernel32ExportDetours::OutputDebugStringA # GetOutputStatus says MFT_OUTPUT_STATUS_SAMPLE_READY
23816,3D70 10:43:31.09833 CKernel32ExportDetours::OutputDebugStringA # GetInputStatus says does NOT accept data
23816,3D70 10:43:31.09834 CKernel32ExportDetours::OutputDebugStringA # ----------------------------------ProcessOutput----------------------------------
23816,3D70 10:43:31.09834 CMFTransformDetours::ProcessMessage #00000229F1932698 Message type=0x10000000 MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, param=00000000
23816,3D70 10:43:31.09835 CMFTransformDetours::ProcessOutput #00000229F1932698 failed hr=0xC00D6D72 MF_E_TRANSFORM_NEED_MORE_INPUT
23816,3D70 10:43:31.09835 CKernel32ExportDetours::OutputDebugStringA # ProcessOutput needs more input
23816,3D70 10:43:31.09836 CKernel32ExportDetours::OutputDebugStringA # GetInputStatus says MFT_INPUT_STATUS_ACCEPT_DATA
As mentioned in the comments, after spending a bit of time with your code, I was able to reproduce the behavior you reported. However, this was also true when I used arbitrary files for input. Admittedly, I was surprised to see that the decoder reported a status of MFT_OUTPUT_STATUS_SAMPLE_READY. Therefore, I agree with Ben regarding valid AAC data.
Instead of parsing the samples manually, perhaps you could simply use an IMFSourceReader to provide the samples for you, which would look similar to the following:
ERROR checking omitted for brevity
HRESULT configure_reader(IMFSourceReader *reader, IMFMediaType **resultingMediaType)
{
HRESULT hr = S_OK;
IMFMediaType *pcmMediaType = NULL;
IMFMediaType *partialType = NULL;
// Create a partial media type that specifies uncompressed PCM audio.
hr = MFCreateMediaType(&partialType);
hr = partialType->lpVtbl->SetGUID(partialType, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
hr = partialType->lpVtbl->SetGUID(partialType, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
// Set this type on the source reader. The source reader will load the necessary decoder.
hr = reader->lpVtbl->SetCurrentMediaType(reader,
(DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM,
NULL,
partialType);
// Get the complete uncompressed format.
hr = reader->lpVtbl->GetCurrentMediaType(reader,
(DWORD) MF_SOURCE_READER_FIRST_AUDIO_STREAM,
&pcmMediaType);
// Ensure the stream is selected.
hr = reader->lpVtbl->SetStreamSelection(reader,
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
TRUE);
if (resultingMediaType)
{
*resultingMediaType = pcmMediaType;
(*resultingMediaType)->lpVtbl->AddRef(*resultingMediaType);
}
(void) pcmMediaType->lpVtbl->Release(pcmMediaType);
(void) partialType->lpVtbl->Release(partialType);
return hr;
}
// . . . . . . . . . . . . . . . . . . . . . .
void process_aac_audio()
{
HRESULT hr = S_OK;
IMFSourceReader *reader = NULL;
hr = MFCreateSourceReaderFromURL(L"input.aac",
NULL,
&reader);
IMFMediaType *pcm_media_type = NULL;
hr = configure_reader(reader, &pcm_media_type);
assert(pcm_media_type);
DWORD total_bytes = 0;
DWORD buffer_length = 0;
BYTE *audioData = NULL;
IMFSample *sample = NULL;
IMFMediaBuffer *mediaBuffer = NULL;
while (1)
{
DWORD dwFlags = 0;
hr = reader->lpVtbl->ReadSample(reader,
(DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM,
0,
NULL,
&dwFlags,
NULL,
&sample);
if (FAILED(hr)) { break; }
if (dwFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)
{
printf("Type change \n");
// TODO:
}
if (dwFlags & MF_SOURCE_READERF_ENDOFSTREAM)
{
printf("End of input file. \n");
break;
}
if (sample == NULL)
{
printf("No sample \n");
continue;
}
hr = sample->lpVtbl->ConvertToContiguousBuffer(sample, &mediaBuffer);
hr = mediaBuffer->lpVtbl->Lock(mediaBuffer, &audioData, NULL, &buffer_length);
// TODO: process buffer
hr = mediaBuffer->lpVtbl->Unlock(mediaBuffer);
audioData = NULL;
total_bytes += buffer_length; // <-- update running total
(void) sample->lpVtbl->Release(sample);
(void) mediaBuffer->lpVtbl->Release(mediaBuffer);
}
if (sample)
(void) sample->lpVtbl->Release(sample);
if (mediaBuffer)
(void) mediaBuffer->lpVtbl->Release(mediaBuffer);
}
In this case the decoder was loaded and employed for you to deliver PCM samples directly. The file you provided (input.txt) failed, however other valid aac files worked fine.
You may be dealing with a stream instead of a file. In that situation, create a source with code similar to the following:
HRESULT create_media_source(IMFByteStream *byteStream, IMFMediaSource **ppSource)
{
MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;
IMFSourceResolver* sourceResolver = NULL;
IUnknown* source = NULL;
HRESULT hr = MFCreateSourceResolver(&sourceResolver);
hr = sourceResolver->lpVtbl->CreateObjectFromByteStream(sourceResolver,
byteStream,
NULL, // URL
MF_RESOLUTION_MEDIASOURCE,
NULL, // IPropertyStore
&objectType,
&source);
// get the IMFMediaSource interface from the media source.
hr = source->lpVtbl->QueryInterface(source, &IID_IMFMediaSource, ppSource);
(void) sourceResolver->lpVtbl->Release(sourceResolver);
(void) source->lpVtbl->Release(source);
return hr;
}
However, note that CreateObjectFromByteStream needs a way to identify the content type. You can either implement IMFAttributes [specifically GetAllocatedString] on your byte stream or pass in a URL

How Copy frame to farme

How can a variable in one frame to another frame it is that kind of copy that is not a memory management problem
for example :
iplimage *frame = NULL;
iplimage *Temp_frame = NULL;
while(1) {
frame = cvQueryFrame( capture );
if( !frame ) break;
Temp_frame=cvcloneimage(frame);
cvreleaseImage(&Temp_frame);
cvreleaseImage(&frame);
}
Error:
Unhandled exception at 0x75b39673 in open cv.exe: Microsoft C++ exception: cv::Exception at memory location 0x0015f250..
Please help.
iplimage *frame = NULL;
iplimage *Temp_frame = NULL;
while(1)
{
frame = cvQueryFrame(capture);
if (!frame)
break;
if (!Temp_frame) // creates Temp_frame only once
Temp_frame = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
cvCopy(frame , Temp_frame, NULL);
// DO NOT RELEASE the return of cvQueryFrame()!
// I believe that's what crashing your application.
//cvreleaseImage(&frame);
}
// Since the size of "frame" won't change, there's no need to to create/release
// Temp_frame on every iteration of the loop. So we release it at the end:
cvReleaseImage(&Temp_frame);

DirSync Page Size option

In my app i need to do a DirSync with the active directory. However, in my search preferences when i try to give the search preference parameter for page size, it shoots me an error (0x80005008, ADS_BAD_PARAMETER). If i dont give that, it works fine. I am giving the code snippet below:
HRESULT DoDirSyncSearch(
LPWSTR pszSearchFilter, // Search filter.
LPWSTR *pAttributeNames, // Attributes to retrieve.
DWORD dwAttributes, // Number of attributes.
PUCHAR *ppCookie, // Pointer to previous cookie.
PULONG pulCookieLength, // Length of previous cookie.
LPWSTR szDC) // Name of DC to bind to.
{
IADs *pRootDSE = NULL;
IDirectorySearch *pSearch = NULL;
ADS_SEARCH_HANDLE hSearch = NULL;
ADS_SEARCHPREF_INFO arSearchPrefs[4];
ADS_PROV_SPECIFIC dirsync;
ADS_SEARCH_COLUMN col;
HRESULT hr = S_OK;
VARIANT var;
BOOL bUpdate = FALSE;
DWORD dwCount = 0;
BOOL noMoreData = false;
DWORD dwError = ERROR_SUCCESS;
WCHAR szError[512];
WCHAR szProvider[512];
// Validate input parameters.
if (!pulCookieLength || !ppCookie || !szDC)
{
wprintf(L"Invalid parameter.\n");
return E_FAIL;
}
LPOLESTR szDSPath = new OLECHAR[MAX_PATH];
LPOLESTR szServerPath = new OLECHAR[MAX_PATH];
VariantInit(&var);
// If cookie is non-NULL, this is an update. Otherwise, it is a full-read.
if (*ppCookie)
bUpdate = TRUE;
CoInitialize(NULL);
// If there is a DC name from the previous USN sync,
// include it in the binding string.
if (szDC[0])
{
wcsncpy_s(szServerPath,MAX_PATH,L"LDAP://",MAX_PATH);
wcsncat_s(szServerPath, MAX_PATH,szDC,MAX_PATH-wcslen(szServerPath));
wcsncat_s(szServerPath, MAX_PATH,L"/",MAX_PATH-wcslen(szServerPath));
}
else
wcsncpy_s(szServerPath, MAX_PATH,L"LDAP://",MAX_PATH);
// Bind to root DSE.
wcsncpy_s(szDSPath,MAX_PATH,szServerPath,MAX_PATH);
wcsncat_s(szDSPath, MAX_PATH,L"rootDSE",MAX_PATH-wcslen(szDSPath));
wprintf(L"RootDSE binding string: %s\n", szDSPath);
hr = ADsGetObject(szDSPath,
IID_IADs,
(void**)&pRootDSE);
if (FAILED(hr))
{
wprintf(L"failed to bind to rootDSE: 0x%x\n", hr);
goto cleanup;
}
// Save the name of the DC connected to in order to connect to
// the same DC on the next dirsync operation.
if (! szDC[0])
{
hr = pRootDSE->Get(CComBSTR("DnsHostName"), &var);
wcsncpy_s(szServerPath,MAX_PATH,L"LDAP://",MAX_PATH);
wcsncat_s(szServerPath, MAX_PATH,var.bstrVal, MAX_PATH-wcslen(szServerPath));
wcsncat_s(szServerPath, MAX_PATH,L"/", MAX_PATH-wcslen(szServerPath));
}
// Get an IDirectorySearch pointer to the root of the domain partition.
hr = pRootDSE->Get(CComBSTR("defaultNamingContext"), &var);
wcsncpy_s(szDSPath,MAX_PATH,szServerPath,MAX_PATH);
wcsncat_s(szDSPath, MAX_PATH,var.bstrVal, MAX_PATH - wcslen(szDSPath));
hr = ADsGetObject(szDSPath, IID_IDirectorySearch, (void**) &pSearch);
if (FAILED(hr))
{
wprintf(L"failed to get IDirectorySearch: 0x%x\n", hr);
goto cleanup;
}
while(noMoreData == false) {
// Initialize the structure to pass in the cookie.
// On the first call, the cookie is NULL and the length is zero.
// On later calls, the cookie and length are the values returned by
// the previous call.
dirsync.dwLength = *pulCookieLength;
dirsync.lpValue = *ppCookie;
arSearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
arSearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
arSearchPrefs[0].vValue.Integer = ADS_SCOPE_SUBTREE;
arSearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_DIRSYNC;
arSearchPrefs[1].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
arSearchPrefs[1].vValue.ProviderSpecific = dirsync;
arSearchPrefs[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
arSearchPrefs[2].vValue.dwType = ADSTYPE_INTEGER;
arSearchPrefs[2].vValue.Integer = 100;
hr = pSearch->SetSearchPreference(arSearchPrefs, 3); // this is where error is happening
if (FAILED(hr))
{
wprintf(L"failed to set search prefs: 0x%x\n", hr);
goto cleanup;
}
// Search for the objects indicated by the search filter.
hr = pSearch->ExecuteSearch(pszSearchFilter,
pAttributeNames, dwAttributes, &hSearch );
if (FAILED(hr))
{
wprintf(L"failed to set execute search: 0x%x\n", hr);
goto cleanup;
}
// Loop through the rows of the search result
// Each row is an object that has changed since the previous call.
hr = pSearch->GetNextRow(hSearch);
while ( SUCCEEDED(hr) && hr != S_ADS_NOMORE_ROWS )
{
hr = pSearch->GetColumn( hSearch, L"distinguishedName", &col );
if ( SUCCEEDED(hr) )
{
wprintf(L"Distinguished Name: %s\n",col.pADsValues->CaseIgnoreString);
pSearch->FreeColumn( &col );
}
dwCount++;
hr = pSearch->GetNextRow( hSearch);
}
ADsGetLastError(&dwError, szError, 512, szProvider, 512);
if(ERROR_MORE_DATA == dwError)
{
noMoreData = false;
wprintf(L"Trying to get cookie...\n");
wprintf(L"Page ends here...\n");
hr = pSearch->GetColumn( hSearch, ADS_DIRSYNC_COOKIE, &col );
if ( SUCCEEDED(hr) ) {
if (col.dwADsType == ADSTYPE_PROV_SPECIFIC && col.pADsValues)
{
wprintf(L"Got cookie\n");
*pulCookieLength = col.pADsValues->ProviderSpecific.dwLength;
*ppCookie = (PUCHAR) AllocADsMem (*pulCookieLength);
memcpy(*ppCookie, col.pADsValues->ProviderSpecific.lpValue,
*pulCookieLength);
}
pSearch->FreeColumn( &col );
} else {
wprintf(L"no cookie: 0x%x\n", hr);
wprintf(L"Error!! More data available but could not continue because of error in cookie retrieval...\n");
noMoreData = true;
}
}
else
noMoreData = true;
}
wprintf(L"dwCount: %d\n", dwCount);
// After looping through the results, get the cookie.
if (hr == S_ADS_NOMORE_ROWS )
{
if (ppCookie != NULL)
{
// Free the existing heap allocation
GlobalFree (*ppCookie);
}
wprintf(L"Trying to get cookie...\n");
hr = pSearch->GetColumn( hSearch, ADS_DIRSYNC_COOKIE, &col );
if ( SUCCEEDED(hr) ) {
if (col.dwADsType == ADSTYPE_PROV_SPECIFIC && col.pADsValues)
{
wprintf(L"Got cookie\n");
*pulCookieLength = col.pADsValues->ProviderSpecific.dwLength;
*ppCookie = (PUCHAR) AllocADsMem (*pulCookieLength);
memcpy(*ppCookie, col.pADsValues->ProviderSpecific.lpValue,
*pulCookieLength);
}
pSearch->FreeColumn( &col );
} else
wprintf(L"no cookie: 0x%x\n", hr);
}
cleanup:
if (pRootDSE)
pRootDSE->Release();
if (hSearch)
pSearch->CloseSearchHandle(hSearch);
if (pSearch)
pSearch->Release();
VariantClear(&var);
CoUninitialize();
delete [] szServerPath;
delete [] szDSPath;
return hr;
}
if i give only 2 first preferences, i.e. Scope and DIRSYNC, then the line
hr = pSearch->SetSearchPreference(arSearchPrefs, 2);
does not give any error.
Can anyone please help me why it is happening. I have checked the way the option for paging is to be specified from msdn : http://msdn.microsoft.com/en-us/library/windows/desktop/aa746414(v=vs.85).aspx
Thanks in advance!
From MSDN link:
ADS_SEARCHPREF_DIRSYNC
Specifies a directory synchronization (DirSync)
search, which returns all changes since a specified state. In the
ADSVALUE structure, set the dwType member to ADS_PROV_SPECIFIC. The
ProviderSpecific member is an ADS_PROV_SPECIFIC structure whose
lpValue member specifies a cookie that indicates the state from which
changes are retrieved. The first time you use the DirSync control, set
the dwLength and lpValue members of the ADS_PROV_SPECIFIC structure to
zero and NULL respectively. After reading the results set returned by
the search until IDirectorySearch::GetNextRow returns
S_ADS_NOMORE_ROWS, call IDirectorySearch::GetColumn to retrieve the
ADS_DIRSYNC_COOKIE attribute which contains a cookie to use in the
next DirSync search. For more information, see Polling for Changes
Using the DirSync Control and LDAP_SERVER_DIRSYNC_OID. This flag
cannot be combined with ADS_SEARCHPREF_PAGESIZE. The caller must have
the SE_SYNC_AGENT_NAME privilege.

Checkers game in SDL

i'm trying to make a checkers game and atm i'm doing the interface with SDL, but i'm just learning C and SDL, how can I move a surface I added to the screen ? I want it the simplest as possible, just remove from X and show on Y, how do I remove a surface to make it appear on another place on the screen ? here is my code:
#include "SDL.h"
#define BRANCA 2
#define PRETA 1
#define DAMA 2
#define NORMAL 1
//The attributes of the screen
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
//The surfaces that will be used
SDL_Surface *pecaPreta = NULL;
SDL_Surface *pecaBranca = NULL;
SDL_Surface *pecaDamaPreta = NULL;
SDL_Surface *pecaDamaBranca = NULL;
SDL_Surface *background = NULL;
SDL_Surface *screen = NULL;
SDL_Event event;
SDL_Surface *load_image(char * filename )
{
SDL_Surface* loadedImage = NULL;
SDL_Surface* optimizedImage = NULL;
loadedImage = SDL_LoadBMP(filename);
if( loadedImage != NULL )
{
optimizedImage = SDL_DisplayFormat( loadedImage );
SDL_FreeSurface( loadedImage );
if( optimizedImage != NULL )
{
Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );
SDL_SetColorKey( optimizedImage, SDL_SRCCOLORKEY, colorkey );
}
}
return optimizedImage;
}
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, destination, &offset );
}
void inserePeca(int tipo, int posX, int posY, int cor)
{
switch(cor)
{
case 1:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaPreta, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaPreta, screen);
break;
}
break;
case 2:
switch (tipo)
{
case 1:
apply_surface(posX, posY, pecaBranca, screen);
break;
case 2:
apply_surface(posX, posY, pecaDamaBranca, screen);
break;
}
break;
}
}
int main()
{
int quit = 0;
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return 1;
}
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
if( screen == NULL )
{
return 1;
}
//Set the window caption
SDL_WM_SetCaption( "Jogo de Damas 0.1b", NULL );
//Load the images
pecaPreta = load_image( "pecapreta.bmp" );
pecaBranca = load_image("pecabranca.bmp");
pecaDamaPreta = load_image("pecadamapreta.bmp");
pecaDamaBranca = load_image("pecadamabranca.bmp");
background = load_image( "tabuleiro.bmp" );
//Apply the background to the screen
apply_surface( 0, 0, background, screen );
inserePeca(DAMA, 0,0, BRANCA);
inserePeca(NORMAL, 80,0, PRETA);
//Update the screen
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
while( quit == 0 )
{
//While there's an event to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if( event.type == SDL_QUIT )
{
//Quit the program
quit = -1;
}
}
}
//Free the surfaces
SDL_FreeSurface( pecaPreta );
SDL_FreeSurface( background );
//Quit SDL
SDL_Quit();
return 0;
}
as you can see I add a block on "inserePeca", I want to move it after I create it
The buffer for the screen doesn't keep all the things you draw on it as separate items -- it just holds the end result of all the drawing operations. So, you can't just draw the background, then draw a piece on it, then move the piece around -- you need to redraw the affected parts of the screen with the required changes.
You still have the images of the pieces, and you still have the background image; the way to move a piece you've drawn is simply to restore the background to the old position by blitting it again, and then blit the piece in the new position. Rather than drawing the whole screen and all the pieces over again, though, you can just draw the changed areas: blit just a part of the background to erase the old square, and then blit the piece onto the new square.
The following function is similar to your apply_surface() function, but instead of copying the whole source image to the the given coordinates of the destination, it copies a region of a given width and height from the given coordinates of the source image to the same coordinates of the destination. This can then be used to restore the background for a small part of the screen.
/* Blit a region from src to the corresponding region in dest. Uses the same
* x and y coordinates for the regions in both src and dest. w and h give the
* width and height of the region, respectively.
*/
void erase_rect( int x, int y, int w, int h, SDL_Surface *src, SDL_Surface *dest)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
offset.w = w;
offset.h = h;
SDL_BlitSurface( src, &offset, dest, &offset );
}
So if your squares are 50x50, and you need to move a piece from a square at (120, 40) to the square at (170, 90), you could do something like the following:
/* erase old 50x50 square at (120,40) (to background image) */
erase_rect( 120, 40, 50, 50, background, screen );
/* draw piece at new position of (170,90) */
inserePeca(NORMAL, 170, 90, PRETA);

WinVerifyTrust to check for a specific signature?

I'm implementing a process elevation helper for Windows. It's a program that will run in elevated mode and launch other programs with administrator privileges without displaying additional UAC prompts. For security reasons, I want to make sure only binaries that are digitally signed with my company's Authenticode key can be executed.
The WinVerifyTrust function gets me halfway there, but it only ensures that a binary is signed by some key that is part of Microsoft's chain of trust. Is there a relatively simple way to perform the Authenticode verification AND ensure that it is signed by our private key?
I believe what you're looking for is CryptQueryObject.
With it you should be able to pull the involved certificate out of a PE, and do any additional checks you want.
By way of example, this will get you to a HCRYPTMSG. From there you can use CryptMsgGetParam to pull out whatever you want. I'd hoped to make something more 'robust', but these APIs are pretty hairy insomuch as they require a lot of branching to handle all their return cases.
So, here's a p/invoke-rific c# example (I started in C, but that was basically unreadable):
static class Crypt32
{
//Omitting flag constants; you can look these up in WinCrypt.h
[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
int dwObjectType,
IntPtr pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
out int pdwMsgAndCertEncodingType,
out int pdwContentType,
out int pdwFormatType,
ref IntPtr phCertStore,
ref IntPtr phMsg,
ref IntPtr ppvContext);
}
class Program
{
static void Main(string[] args)
{
//Path to executable here
// I tested with MS-Office .exe's
string path = "";
int contentType;
int formatType;
int ignored;
IntPtr context = IntPtr.Zero;
IntPtr pIgnored = IntPtr.Zero;
IntPtr cryptMsg = IntPtr.Zero;
if (!Crypt32.CryptQueryObject(
Crypt32.CERT_QUERY_OBJECT_FILE,
Marshal.StringToHGlobalUni(path),
Crypt32.CERT_QUERY_CONTENT_FLAG_ALL,
Crypt32.CERT_QUERY_FORMAT_FLAG_ALL,
0,
out ignored,
out contentType,
out formatType,
ref pIgnored,
ref cryptMsg,
ref context))
{
int error = Marshal.GetLastWin32Error();
Console.WriteLine((new Win32Exception(error)).Message);
return;
}
//expecting '10'; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
Console.WriteLine("Context Type: " + contentType);
//Which implies this is set
Console.WriteLine("Crypt Msg: " + cryptMsg.ToInt32());
return;
}
To get the certificate information from signed code use this:
using System.Security.Cryptography.X509Certificates;
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(filename);
X509Certificate2 cert = new X509Certificate2(basicSigner);
Then you can get the cert details like this:
Console.WriteLine(cert.IssuerName.Name);
Console.WriteLine(cert.SubjectName.Name);
// etc
these are some of the nastiest APIs I've ever worked with
A word of warning: it's worse than you already thought.
At least since introducing SHA-256 signing (has this always been the case?), it's possible for Authenticode to have multiple signatures. They're not encoded as multiple signatures in the PKCS-7 signature message; instead, they're unauthenticated message attributes of type OID_NESTED_SIGNATURE, each containing another complete PKCS-7 signature message.
WinVerifyTrust will tell you the file is valid if any of the signatures are valid and come from a trusted certificate chain. However it won't tell you which of the signatures was valid. If you then use CryptQueryObject to read the full PKCS-7 message, and only look at the certificate for the primary signature (as in the code samples here and on MSDN), you're not necessarily looking at a verified certificate. The associated signature might not match the executable, and/or the certificate might not have a trusted CA chain.
If you're using the details of the primary signature to validate that the certificate is one your software trusts, you're vulnerable to a situation where WinVerifyTrust is trusting a secondary signature, but your code is checking the primary signature's certificate is what you expected, and you haven't noticed that the signature from the primary certificate is nonsense. An attacker could use your public certificate without owning its private key, combined with some other code-signing certificate issued to someone else, to bypass a publisher check this way.
From Win8 onwards, WinVerifyTrust can optionally validate specific signatures, so you should be able to iterate the signatures to find one that is valid and one that satisfies your requirements.
If you have to be Win7-compatible, though, as far as I know the best you can manage is MsiGetFileSignatureInformation. From experimentation (as for everything else here, the actual documentation is frustratingly woolly), it seems to return the trusted certificate when WinVerifyTrust trusts one. But if there isn't a trusted signature, it returns the primary signature's certificate anyway, so you still have to use WinVerifyTrust to check that first.
Of course there also plenty of possible time-of-check/time-of-use problems here.
found the solution here:
http://www.ucosoft.com/how-to-program-to-retrieve-the-authenticode-information.html
here it is with indentation:
#define _UNICODE 1
#define UNICODE 1
#include <windows.h>
#include <tchar.h>
#include <wincrypt.h>
#include <Softpub.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment (lib, "Crypt32")
// the Authenticode Signature is encode in PKCS7
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
// Information structure of authenticode sign
typedef struct
{
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
DWORD cbSerialSize;
LPBYTE lpSerialNumber;
LPTSTR lpszIssuerName;
LPTSTR lpszSubjectName;
}
SPROG_SIGNATUREINFO, *PSPROG_SIGNATUREINFO;
VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo);
VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo);
BOOL GetAuthenticodeInformation(LPCTSTR lpszFileName, PSPROG_SIGNATUREINFO pInfo)
{
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
DWORD dwSignerInfo;
BOOL bRet = FALSE;
__try
{
// as CryptQueryObject() only accept WCHAR file name, convert first
WCHAR wszFileName[MAX_PATH];
#ifdef UNICODE
if ( !lstrcpynW( wszFileName, lpszFileName, MAX_PATH))
__leave;
#else
if ( mbstowcs( wszFileName, lpszFileName, MAX_PATH) == -1)
__leave;
#endif
//Retrieve the Message Handle and Store Handle
DWORD dwEncoding, dwContentType, dwFormatType;
if ( !CryptQueryObject( CERT_QUERY_OBJECT_FILE, wszFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding,
&dwContentType, &dwFormatType, &hStore,
&hMsg, NULL))
__leave;
//Get the length of SignerInfo
if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo))
__leave;
// allocate the memory for SignerInfo
if ( !(pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc( LPTR, dwSignerInfo)))
__leave;
// get the SignerInfo
if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo))
__leave;
//get the Publisher from SignerInfo
GetProgAndPublisherInfo( pSignerInfo, pInfo);
//get the Certificate from SignerInfo
GetCertificateInfo( hStore, pSignerInfo, pInfo);
bRet = TRUE;
}
__finally
{
// release the memory
if (pSignerInfo != NULL) LocalFree(pSignerInfo);
if (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return bRet;
}
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;
// allocate the memory
outputString = (LPWSTR)VirtualAlloc(NULL, (wcslen(inputString) + 1) * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE);
// copy
if (outputString != NULL)
{
lstrcpyW(outputString, inputString);
}
return outputString;
}
VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo)
{
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
__try
{
// query SPC_SP_OPUS_INFO_OBJID OID in Authenticated Attributes
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// get the length of SPC_SP_OPUS_INFO
if ( !CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwData))
__leave;
// allocate the memory for SPC_SP_OPUS_INFO
if ( !(OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData)))
__leave;
// get SPC_SP_OPUS_INFO structure
if ( !CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
OpusInfo,
&dwData))
__leave;
// copy the Program Name of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pwszProgramName)
{
pInfo->lpszProgramName = AllocateAndCopyWideString(OpusInfo->pwszProgramName);
}
else
pInfo->lpszProgramName = NULL;
// copy the Publisher Info of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pPublisherInfo)
{
switch (OpusInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pInfo->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pInfo->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
break;
default:
pInfo->lpszPublisherLink = NULL;
break;
}
}
else
{
pInfo->lpszPublisherLink = NULL;
}
// copy the More Info of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pMoreInfo)
{
switch (OpusInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pInfo->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pInfo->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
break;
default:
pInfo->lpszMoreInfoLink = NULL;
break;
}
}
else
{
pInfo->lpszMoreInfoLink = NULL;
}
break; // we have got the information, break
}
}
}
__finally
{
if (OpusInfo != NULL) LocalFree(OpusInfo);
}
}
VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
__try
{
CERT_INFO CertInfo;
DWORD dwData;
// query Signer Certificate in Certificate Store
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
if ( !(pCertContext = CertFindCertificateInStore( hStore,
ENCODING, 0, CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo, NULL)))
__leave;
dwData = pCertContext->pCertInfo->SerialNumber.cbData;
// SPROG_SIGNATUREINFO.cbSerialSize
pInfo->cbSerialSize = dwData;
// SPROG_SIGNATUREINFO.lpSerialNumber
pInfo->lpSerialNumber = (LPBYTE)VirtualAlloc(NULL, dwData, MEM_COMMIT, PAGE_READWRITE);
memcpy( pInfo->lpSerialNumber, pCertContext->pCertInfo->SerialNumber.pbData, dwData);
// SPROG_SIGNATUREINFO.lpszIssuerName
__try
{
// get the length of Issuer Name
if (!(dwData = CertGetNameString( pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, NULL, 0)))
__leave;
// allocate the memory
if ( !(pInfo->lpszIssuerName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE)))
__leave;
// get Issuer Name
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, pInfo->
lpszIssuerName, dwData)))
__leave;
}
__finally
{
}
// SPROG_SIGNATUREINFO.lpszSubjectName
__try
{
//get the length of Subject Name
if (!(dwData = CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0)))
__leave;
// allocate the memory
if ( !(pInfo->lpszSubjectName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE)))
__leave;
// get Subject Name
if (!(CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pInfo->lpszSubjectName, dwData)))
__leave;
}
__finally
{
}
}
__finally
{
if (pCertContext != NULL)
CertFreeCertificateContext(pCertContext);
}
}
int _tmain(int argc, TCHAR *argv[])
{
if (argc != 2)
{
_tprintf(_T("Usage: SignedFileInfo \n"));
return 0;
}
else
{
SPROG_SIGNATUREINFO SignInfo;
ZeroMemory(&SignInfo, sizeof(SignInfo));
GetAuthenticodeInformation( argv[1], &SignInfo);
wprintf(L"Program Name: %s\n", SignInfo.lpszProgramName);
wprintf(L"Publisher Link: %s\n", SignInfo.lpszPublisherLink);
wprintf(L"More Info Link: %s\n", SignInfo.lpszMoreInfoLink);
{
_tprintf(_T("Serial Number: "));
DWORD dwData = SignInfo.cbSerialSize;
for (DWORD n = 0; n < dwData; n++)
{
_tprintf(_T("%02x "),
SignInfo.lpSerialNumber[dwData - (n + 1)]);
}
_tprintf(_T("\n"));
}
_tprintf(_T("Issuer Name: %s\n"), SignInfo.lpszIssuerName);
_tprintf(_T("Subject Name: %s\n"), SignInfo.lpszSubjectName);
if ( SignInfo.lpszProgramName) VirtualFree(SignInfo.lpszProgramName, 0, MEM_RELEASE);
if ( SignInfo.lpszPublisherLink) VirtualFree(SignInfo.lpszPublisherLink, 0, MEM_RELEASE);
if ( SignInfo.lpszMoreInfoLink) VirtualFree(SignInfo.lpszMoreInfoLink, 0, MEM_RELEASE);
if ( SignInfo.lpSerialNumber) VirtualFree(SignInfo.lpSerialNumber, 0, MEM_RELEASE);
if ( SignInfo.lpszIssuerName) VirtualFree(SignInfo.lpszIssuerName, 0, MEM_RELEASE);
if ( SignInfo.lpszSubjectName) VirtualFree(SignInfo.lpszSubjectName, 0, MEM_RELEASE);
return 0;
}
}

Resources