Related
I'm trying to use CVOpenGLESTextureCacheCreateTextureFromImage in order to use the reference in OpenGL, with no luck:
I have a CVPixelBufferRef pixel_bufferAlpha which gets updated using CVPixelBufferCreateWithBytes, with success :
CVReturn is successfull.
Then I try to use CVOpenGLESTextureCacheCreateTextureFromImage on a 1 channel texture ( alphaMatte ) to create a CVOpenGLESTextureRef that i can use in OpenGL.
I have initialised my CVOpenGLESTextureCacheRef _videoTextureAlphaCache :
err = CVOpenGLESTextureCacheCreate(
kCFAllocatorDefault,
nil,
eaglContext,
nil,
&_videoTextureAlphaCache);
And my CVPixelBufferRef pixel_bufferAlpha is initialised using :
cvret = CVPixelBufferCreate(kCFAllocatorDefault,
width,height,
kCVPixelFormatType_OneComponent8,
(__bridge CFDictionaryRef)cvBufferProperties,
&pixel_bufferAlpha);
if(cvret != kCVReturnSuccess)
{
assert(!"Failed to create shared opengl pixel_bufferAlpha");
}
I'm using kCVPixelFormatType_OneComponent8, as my MTLTexture passed in CVPixelBufferCreateWithBytes has a MTLPixelFormat 10 - > MTLPixelFormatR8Unorm.
When trying to use CVOpenGLESTextureCacheCreateTextureFromImage, I get an error "not opengl compatible" :
CVPixelBufferLockBaseAddress(pixel_bufferAlpha, 0);
err = noErr;
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
_videoTextureAlphaCache,
pixel_bufferAlpha,
NULL,
GL_TEXTURE_2D,
// internal
// GL_RGBA,
GL_ALPHA,
width,
height,
// gl format
// GL_BGRA_EXT,
// GL_R8_EXT,
GL_ALPHA8_EXT,
// gl type
// GL_UNSIGNED_INT_8_8_8_8_REV,
GL_UNSIGNED_BYTE,
NULL,
&alphaTextureGLES);
if (err != kCVReturnSuccess) {
CVBufferRelease(pixel_bufferAlpha);
if(err == kCVReturnInvalidPixelFormat){
NSLog(#"Invalid pixel format");
}
if(err == kCVReturnInvalidPixelBufferAttributes){
NSLog(#"Invalid pixel buffer attributes");
}
if(err == kCVReturnInvalidSize){
NSLog(#"invalid size");
}
if(err == kCVReturnPixelBufferNotOpenGLCompatible){
NSLog(#"CVOpenGLESTextureCacheCreateTextureFromImage::not opengl compatible");
}
}else{
NSLog(#"ok CVOpenGLESTextureCacheCreateTextureFromImage SUCCESS");
}
// ================================================================================ //
// clear texture cache
CVOpenGLESTextureCacheFlush(_videoTextureAlphaCache, 0);
CVPixelBufferUnlockBaseAddress(pixel_bufferAlpha, 0);
I'm not sure what I' doing wrong here.
Also I would appreciate any pointers as I'm not super versed in iOS and textures conversions / formats...
Best,
P
Full relevant part of the code :
alphaTexture = [matteDepthTexture generateMatteFromFrame:_session.currentFrame commandBuffer:commandBuffer];
// ===============================================================
NSUInteger texBytesPerRow = alphaTexture.bufferBytesPerRow;
NSUInteger texArrayLength = alphaTexture.arrayLength;
int width = (int) alphaTexture.width;
int height = (int) alphaTexture.height;
MTLPixelFormat texPixelFormat = alphaTexture.pixelFormat;
MTLTextureType texType = alphaTexture.textureType;
int bytesPerPixel = 8;
// MTLPixelFormatR8Unorm Ordinary format with one 8-bit normalized unsigned integer component.
NSLog(#" texPixelFormat of the texture is : %d", texPixelFormat);
NSLog(#" texType of the texture is : %d", texType);
CVReturn err = noErr;
err = CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
width,
height,
kCVPixelFormatType_OneComponent8,
alphaTexture,
bytesPerPixel * width,
stillImageDataReleaseCallback,
alphaTexture,
NULL,
&pixel_bufferAlpha);
if (err != kCVReturnSuccess) {
if(err == kCVReturnInvalidPixelFormat){
NSLog(#"Invalid pixel format");
}
if(err == kCVReturnInvalidPixelBufferAttributes){
NSLog(#"Invalid pixel buffer attributes");
}
if(err == kCVReturnInvalidSize){
NSLog(#"invalid size");
}
if(err == kCVReturnPixelBufferNotOpenGLCompatible){
NSLog(#"CVPixelBufferCreateWithBytes::not opengl compatible");
}
}else{
NSLog(#"ok CVPixelBufferCreateWithBytes SUCCESS");
}
OSType sourcePixelFormat = CVPixelBufferGetPixelFormatType(pixel_bufferAlpha);
if (kCVPixelFormatType_OneComponent8 == sourcePixelFormat) {
NSLog(#" got format kCVPixelFormatType_OneComponent8");
} else{
NSLog(#" Unknown CoreVideo pixel format : %a", sourcePixelFormat);
}
// ================================================================================ //
CVPixelBufferLockBaseAddress(pixel_bufferAlpha, 0);
err = noErr;
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
_videoTextureAlphaCache,
pixel_bufferAlpha,
NULL,
GL_TEXTURE_2D,
// internal
// GL_RGBA,
GL_RED_EXT,
width,
height,
// gl format
// GL_BGRA_EXT,
// GL_R8_EXT,
GL_R8_EXT,
// gl type
// GL_UNSIGNED_INT_8_8_8_8_REV,
GL_UNSIGNED_BYTE,
NULL,
&alphaTextureGLES);
if (err != kCVReturnSuccess) {
CVBufferRelease(pixel_bufferAlpha);
if(err == kCVReturnInvalidPixelFormat){
NSLog(#"Invalid pixel format");
}
if(err == kCVReturnInvalidPixelBufferAttributes){
NSLog(#"Invalid pixel buffer attributes");
}
if(err == kCVReturnInvalidSize){
NSLog(#"invalid size");
}
if(err == kCVReturnPixelBufferNotOpenGLCompatible){
NSLog(#"CVOpenGLESTextureCacheCreateTextureFromImage::not opengl compatible");
}
}else{
NSLog(#"ok CVOpenGLESTextureCacheCreateTextureFromImage SUCCESS");
}
// ================================================================================ //
// clear texture cache
CVOpenGLESTextureCacheFlush(_videoTextureAlphaCache, 0);
CVPixelBufferUnlockBaseAddress(pixel_bufferAlpha, 0);
After digging a bit, I found an extension to MTLtexture from Alloy - great work there - :
here
getBytes to put the texture in a CVPixelBufferRef then
CVOpenGLESTextureCacheCreateTextureFromImage to store it in a CVOpenGLESTextureRef.
So in Objective - C it looks like this - with the same initialisation for the pixel_bufferAlpha and _videoTextureAlphaCache - :
alphaTexture = [matteDepthTexture generateMatteFromFrame:_session.currentFrame commandBuffer:commandBuffer];
int width = (int) alphaTexture.width;
int height = (int) alphaTexture.height;
MTLPixelFormat texPixelFormat = alphaTexture.pixelFormat;
CVPixelBufferLockBaseAddress(pixel_bufferAlpha, 0);
void * CV_NULLABLE pixelBufferBaseAdress = CVPixelBufferGetBaseAddress(pixel_bufferAlpha);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixel_bufferAlpha);
[alphaTexture getBytes:pixelBufferBaseAdress
bytesPerRow:bytesPerRow
fromRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:0];
size_t w = CVPixelBufferGetWidth(pixel_bufferAlpha);
size_t h = CVPixelBufferGetHeight(pixel_bufferAlpha);
CVReturn err = noErr;
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
_videoTextureAlphaCache,
pixel_bufferAlpha,
nil,
GLenum(GL_TEXTURE_2D),
GLint(GL_LUMINANCE),
w,
h,
GLenum(GL_LUMINANCE),
GLenum(GL_UNSIGNED_BYTE),
0,
&alphaTextureGLES);
if (err != kCVReturnSuccess) {
CVBufferRelease(pixel_bufferAlpha);
NSLog(#"error on CVOpenGLESTextureCacheCreateTextureFromImage");
}
CVPixelBufferUnlockBaseAddress(pixel_bufferAlpha, 0);
Hope this helps someone along the way.
I want to implement SIP calls in my application, and first problem, that I need to solve, is converting audio from compressed AAC format with ADTS header to linear PCM.
My input data is an NSArray of ADTS frames with different framesize. Each frame is typeof NSMutableData. Each frame is of the same format and sample rate, only difference is framesize.
I tried to implement sample code, suggested by Igor Rotaru for this issue, but can't make it work.
Now my code looks like this. First of all, I configure the AudioConverter:
- (void)configureAudioConverter {
AudioStreamBasicDescription inFormat;
memset(&inFormat, 0, sizeof(inFormat));
inputFormat.mBitsPerChannel = 0;
inputFormat.mBytesPerFrame = 0;
inputFormat.mBytesPerPacket = 0;
inputFormat.mChannelsPerFrame = 1;
inputFormat.mFormatFlags = kMPEG4Object_AAC_LC;
inputFormat.mFormatID = kAudioFormatMPEG4AAC;
inputFormat.mFramesPerPacket = 1024;
inputFormat.mReserved = 0;
inputFormat.mSampleRate = 22050;
AudioStreamBasicDescription outputFormat;
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mSampleRate = inputFormat.mSampleRate;
outputFormat.mFormatID = kAudioFormatLinearPCM;
outputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
outputFormat.mBytesPerPacket = 2;
outputFormat.mFramesPerPacket = 1;
outputFormat.mBytesPerFrame = 2;
outputFormat.mChannelsPerFrame = 1;
outputFormat.mBitsPerChannel = 16;
outputFormat.mReserved = 0;
AudioClassDescription *description = [self
getAudioClassDescriptionWithType:kAudioFormatMPEG4AAC
fromManufacturer:kAppleSoftwareAudioCodecManufacturer];
OSStatus status = AudioConverterNewSpecific(&inputFormat, &outputFormat, 1, description, &_audioConverter);
if (status != 0) {
printf("setup converter error, status: %i\n", (int)status);
}
}
After that I wrote the callback function:
struct MyUserData {
UInt32 mChannels;
UInt32 mDataSize;
const void* mData;
AudioStreamPacketDescription mPacket;
};
OSStatus inInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData)
{
struct MyUserData* userData = (struct MyUserData*)(inUserData);
if (!userData->mDataSize) {
*ioNumberDataPackets = 0;
return kNoMoreDataError;
}
if (outDataPacketDescription) {
userData->mPacket.mStartOffset = 0;
userData->mPacket.mVariableFramesInPacket = 0;
userData->mPacket.mDataByteSize = userData->mDataSize;
*outDataPacketDescription = &userData->mPacket;
}
ioData->mBuffers[0].mNumberChannels = userData->mChannels;
ioData->mBuffers[0].mDataByteSize = userData->mDataSize;
ioData->mBuffers[0].mData = (void *)userData->mData;
// No more data to provide following this run.
userData->mDataSize = 0;
return noErr;
}
And my function for decoding frames looks like this:
- (void)startDecodingAudio {
if (!_converterConfigured){
return;
}
while (true){
if ([self hasFramesToDecode]){
struct MyUserData userData = {1, (UInt32)_decoderBuffer[_currPosInDecoderBuf].length, _decoderBuffer[_currPosInDecoderBuf].bytes};
uint8_t *buffer = (uint8_t *)malloc(128 * sizeof(short int));
AudioBufferList decBuffer;
decBuffer.mNumberBuffers = 1;
decBuffer.mBuffers[0].mNumberChannels = 1;
decBuffer.mBuffers[0].mDataByteSize = 128 * sizeof(short int);
decBuffer.mBuffers[0].mData = buffer;
UInt32 numFrames = 128;
AudioStreamPacketDescription outPacketDescription;
memset(&outPacketDescription, 0, sizeof(AudioStreamPacketDescription));
outPacketDescription.mDataByteSize = 128;
outPacketDescription.mStartOffset = 0;
outPacketDescription.mVariableFramesInPacket = 0;
OSStatus status = AudioConverterFillComplexBuffer(_audioConverter,
inInputDataProc,
&userData,
&numFrames,
&decBuffer,
&outPacketDescription);
NSError *error = nil;
if (status == kNoMoreDataError) {
NSLog(#"%u bytes decoded", (unsigned int)decBuffer.mBuffers[0].mDataByteSize);
[_decodedData appendData:[NSData dataWithBytes:decBuffer.mBuffers[0].mData length:decBuffer.mBuffers[0].mDataByteSize]];
_currPosInDecoderBuf += 1;
} else {
error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];
}
} else {
break;
}
}
}
Each time, AudioConverterFillComplexBuffer returns status 1852797029 which is, according to Apple API, kAudioCodecIllegalOperationError. If somebody succeded in converting with such formats, please, share some examples, or advice.
Finally, I decoded my bytes with StreamingKit library (original reposiory can be found here).
Recently, my project wants to achieving audio communication by AAC, so i use the AudioQueue, but there is a problem that my player's callback function doesn't work, in my project the callback function has worked 3 times. that is for function work 3 times. and when active AudioQueueStart(mQueue, NULL), the callback function never be called.
I use two iPhone to run. they are connect by udp socket, and i'm sure this part is fine. i can get the correct audio data.
And i modify a demo which is play a file data not memory. so i don't know is it a problem?
here is my code: AQPlayer.h
#include <AudioToolbox/AudioToolbox.h>
#include "CAStreamBasicDescription.h"
#include "CAXException.h"
#define kNumberBuffers 3
#define kBufferDurationSeconds 0.5
class AQPlayer
{
public:
AQPlayer();
~AQPlayer();
OSStatus StartQueue(BOOL inResume);
OSStatus StopQueue();
OSStatus PauseQueue();
AudioQueueRef Queue() { return mQueue; }
CAStreamBasicDescription DataFormat() const { return mDataFormat; }
Boolean IsRunning() const { return (mIsRunning) ? true : false; }
Boolean IsInitialized() const { return mIsInitialized; }
CFStringRef GetFilePath() const { return (mFilePath) ? mFilePath : CFSTR(""); }
Boolean IsLooping() const { return mIsLooping; }
void SetLooping(Boolean inIsLooping) { mIsLooping = inIsLooping; }
void CreateQueueForFile(CFStringRef inFilePath);
void DisposeQueue(Boolean inDisposeFile);
void prepareAudioQueue();
void start();
void stop();
private:
UInt32 GetNumPacketsToRead() { return mNumPacketsToRead; }
SInt64 GetCurrentPacket() { return mCurrentPacket; }
AudioFileID GetAudioFileID() { return mAudioFile; }
void SetCurrentPacket(SInt64 inPacket) { mCurrentPacket = inPacket; }
void SetupNewQueue();
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
AudioFileID mAudioFile;
CFStringRef mFilePath;
CAStreamBasicDescription mDataFormat;
Boolean mIsInitialized;
UInt32 mNumPacketsToRead;
SInt64 mCurrentPacket;
UInt32 mIsRunning;
Boolean mIsDone;
Boolean mIsLooping;
static void isRunningProc( void * inUserData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID);
static void AQBufferCallback( void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer);
void CalculateBytesForTime( CAStreamBasicDescription & inDesc,
UInt32 inMaxPacketSize,
Float64 inSeconds,
UInt32 *outBufferSize,
UInt32 *outNumPackets);
};
and here is AQPlayer.mm
#include "package.h"
#include "udpsocket.h"
#define MAXPACKETSIZE 1000
#define BUFFER_SIZE 4000
#include "AQPlayer.h"
extern udpsocket *udp;
void AQPlayer::AQBufferCallback(void * inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer)
{
AQPlayer *THIS = (AQPlayer *)inUserData;
dispatch_semaphore_wait(udp->sempahore,DISPATCH_TIME_FOREVER);
NSLog(#"read begin");
while ([udp->AudioQueue count]>0 &&
![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
{
[udp->AudioQueue removeObjectAtIndex:0];
}
if([udp->AudioQueue count]<1){
[NSThread sleepForTimeInterval:0.05];
AQBufferCallback(inUserData, inAQ, inCompleteAQBuffer);
return;
}
int packets = 0;
int dataLen = 0;
AUDIO_CACHE_OBJECT *pack;
char *data = (char*)malloc(sizeof(char)*BUFFER_SIZE);;
memset(data, 0, BUFFER_SIZE);
pack = [udp->AudioQueue firstObject];
while (dataLen+pack.datalen<BUFFER_SIZE && [udp->AudioQueue count]>0 /*&& packets<21*/) {
memcpy(data+dataLen, [pack GetData], [pack datalen]);
dataLen+=[pack datalen];
[udp->AudioQueue removeObjectAtIndex:0];
// [pack memset];
packets ++;
while ([udp->AudioQueue count]>1 &&
![[udp->AudioQueue objectAtIndex:0] isKindOfClass:[AUDIO_CACHE_OBJECT class]])
{
[udp->AudioQueue removeObjectAtIndex:0];
}
if([udp->AudioQueue count]<1){
break;
}
pack = [udp->AudioQueue firstObject];
}
memcpy(inCompleteAQBuffer->mAudioData, data, dataLen);
inCompleteAQBuffer->mAudioDataByteSize = dataLen;
inCompleteAQBuffer->mPacketDescriptionCount = packets;
AudioQueueEnqueueBuffer(inAQ, inCompleteAQBuffer, 0,NULL);
THIS->mCurrentPacket += packets;
free(data);
NSLog(#"read end --- %lld",THIS->mCurrentPacket);
}
void AQPlayer::isRunningProc ( void * inUserData,
AudioQueueRef inAQ,
AudioQueuePropertyID inID)
{
AQPlayer *THIS = (AQPlayer *)inUserData;
UInt32 size = sizeof(THIS->mIsRunning);
OSStatus result = AudioQueueGetProperty (inAQ, kAudioQueueProperty_IsRunning, &THIS->mIsRunning, &size);
if ((result == noErr) && (!THIS->mIsRunning))
[[NSNotificationCenter defaultCenter] postNotificationName: #"playbackQueueStopped" object: nil];
}
void AQPlayer::CalculateBytesForTime (CAStreamBasicDescription & inDesc, UInt32 inMaxPacketSize, Float64 inSeconds, UInt32 *outBufferSize, UInt32 *outNumPackets)
{
// we only use time here as a guideline
// we're really trying to get somewhere between 16K and 64K buffers, but not allocate too much if we don't need it
static const int maxBufferSize = 0x10000; // limit size to 64K
static const int minBufferSize = 0x4000; // limit size to 16K
if (inDesc.mFramesPerPacket) {
Float64 numPacketsForTime = inDesc.mSampleRate / inDesc.mFramesPerPacket * inSeconds;
*outBufferSize = numPacketsForTime * inMaxPacketSize;
} else {
// if frames per packet is zero, then the codec has no predictable packet == time
// so we can't tailor this (we don't know how many Packets represent a time period
// we'll just return a default buffer size
*outBufferSize = maxBufferSize > inMaxPacketSize ? maxBufferSize : inMaxPacketSize;
}
// we're going to limit our size to our default
if (*outBufferSize > maxBufferSize && *outBufferSize > inMaxPacketSize)
*outBufferSize = maxBufferSize;
else {
// also make sure we're not too small - we don't want to go the disk for too small chunks
if (*outBufferSize < minBufferSize)
*outBufferSize = minBufferSize;
}
*outNumPackets = *outBufferSize / inMaxPacketSize;
}
AQPlayer::AQPlayer() :
mQueue(0),
mAudioFile(0),
mFilePath(NULL),
mIsRunning(false),
mIsInitialized(false),
mNumPacketsToRead(0),
mCurrentPacket(0),
mIsDone(false),
mIsLooping(false) { }
AQPlayer::~AQPlayer()
{
DisposeQueue(true);
}
OSStatus AQPlayer::StartQueue(BOOL inResume)
{
if (mQueue == NULL)
CreateQueueForFile(mFilePath);
mIsDone = false;
if (!inResume)
mCurrentPacket = 0;
for (int i = 0; i < kNumberBuffers; ++i) {
AQBufferCallback (this, mQueue, mBuffers[i]);
}
NSLog(#"audioqueuestart");
UInt32 i =0;
AudioQueuePrime(mQueue, 0, &i);
NSLog(#"%d",(unsigned int)i);
return AudioQueueStart(mQueue, NULL);
}
OSStatus AQPlayer::StopQueue()
{
OSStatus result = AudioQueueStop(mQueue, true);
if (result) printf("ERROR STOPPING QUEUE!\n");
return result;
}
OSStatus AQPlayer::PauseQueue()
{
OSStatus result = AudioQueuePause(mQueue);
return result;
}
void AQPlayer::CreateQueueForFile(CFStringRef inFilePath)
{
try {
UInt32 size = sizeof(mDataFormat);
mDataFormat.mSampleRate = 44100;
mDataFormat.mFormatID = kAudioFormatMPEG4AAC;
mDataFormat.mFormatFlags = 0;
mDataFormat.mFramesPerPacket = 1024;
mDataFormat.mChannelsPerFrame = 2;
mDataFormat.mBitsPerChannel = 0;//表示这是一个压缩格式
mDataFormat.mBytesPerPacket = 0;//表示这是一个变比特率压缩
mDataFormat.mBytesPerFrame = 0;
mDataFormat.mReserved = 0;
//aqc.bufferByteSize = 2000;
SetupNewQueue();
}
catch (NSException *e) {
fprintf(stderr, "Error: %# (%#)\n", [e debugDescription], [e description]);
}
}
void AQPlayer::SetupNewQueue()
{
AudioQueueNewOutput(&mDataFormat, AQPlayer::AQBufferCallback, this,//NULL,NULL,0,&mQueue);
CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &mQueue);
UInt32 bufferByteSize;
UInt32 maxPacketSize = MAXPACKETSIZE;
UInt32 size = sizeof(maxPacketSize);
CalculateBytesForTime (mDataFormat, maxPacketSize, kBufferDurationSeconds, &bufferByteSize, &mNumPacketsToRead);
size = sizeof(UInt32);
AudioQueueAddPropertyListener(mQueue, kAudioQueueProperty_IsRunning, isRunningProc, this);
bool isFormatVBR = (mDataFormat.mBytesPerPacket == 0 || mDataFormat.mFramesPerPacket == 0);
AudioQueueSetParameter(mQueue, kAudioQueueParam_Volume, 1.0);
for (int i = 0; i < kNumberBuffers; ++i) {
AudioQueueAllocateBuffer(mQueue, bufferByteSize, &mBuffers[i]);
}
// set the volume of the queue
mIsInitialized = true;
}
void AQPlayer::DisposeQueue(Boolean inDisposeFile)
{
if (mQueue)
{
AudioQueueDispose(mQueue, true);
mQueue = NULL;
}
if (inDisposeFile)
{
if (mAudioFile)
{
AudioFileClose(mAudioFile);
mAudioFile = 0;
}
if (mFilePath)
{
CFRelease(mFilePath);
mFilePath = NULL;
}
}
mIsInitialized = false;
}
Thank for your time.
Your input is VBR so your buffers need an accompanying packet description array. Use AudioQueueAllocateBufferWithPacketDescriptions: instead of AudioQueueAllocateBuffer: when you are initially creating your buffers. Then set mStartOffset, mDataByteSize, and mVariableFramesInPacket (always zero) for each packet inside your while loop in your callback procedure.
I'm wanting to display some geometries using the solidwireframe, it appears to be a fx file with multiple effects and single passes.
So i wrote a class to perform what i thought the effect file was doing. The Header files are my Compiled Shaders, which are copies of the NVidia ones. compiled with version 4.0
# include "SolidWireFrame.h"
# include "WireGeometryShader.h"
# include "GeometryShader.h"
# include "WirePixelShader.h"
# include "ColorPixelShader.h"
# include "WireVertexShader.h"
namespace DirectX11DrawingAdapter
{
SolidWireFrame::SolidWireFrame()
{
}
bool SolidWireFrame::Init(ID3D11Device* device)
{
m_pdepthLessEqualStencilState = nullptr;
m_pfillRasterizerState = nullptr;
m_pBlendingState = nullptr;
m_pdepthWriteLessStencilState = nullptr;
m_vertexShader = nullptr;
m_geometryShader = nullptr;
m_pixelColorShader = nullptr;
m_geometrySolidWireShader = nullptr;
m_pixelSolidWireShader = nullptr;
m_vertexLayout = nullptr;
if (!InitializeDepthStencilState(device))
return false;
if (!InitializeRaterizerState(device))
return false;
if (!InitializeBlendState(device))
return false;
if (!InitializeVertexShader(device))
return false;
if (!InitializeGeometryShader(device))
return false;
if (!InitializePixelShader(device))
return false;
return true;
}
void SolidWireFrame::ApplySolidWirePattern(ID3D11DeviceContext* deviceContext)
{
SetDepthStencilState(deviceContext, m_pdepthLessEqualStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->GSSetShader(m_geometrySolidWireShader, NULL, 0);
deviceContext->PSSetShader(m_pixelSolidWireShader, NULL, 0);
}
void SolidWireFrame::ApplyDepthAndSolid(ID3D11DeviceContext* deviceContext)
{
SetDepthStencilState(deviceContext, m_pdepthWriteLessStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->GSSetShader(m_geometryShader, NULL, 0);
deviceContext->PSSetShader(m_pixelColorShader, NULL, 0);
}
void SolidWireFrame::ApplyDepthOnly(ID3D11DeviceContext* deviceContext)
{
SetDepthStencilState(deviceContext, m_pdepthWriteLessStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pnoColorBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->GSSetShader(m_geometryShader, NULL, 0);
deviceContext->PSSetShader(m_pixelColorShader, NULL, 0);
}
void SolidWireFrame::ApplySolidOnly(ID3D11DeviceContext* deviceContext)
{
SetDepthStencilState(deviceContext, m_pdepthLessEqualStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->GSSetShader(m_geometryShader, NULL, 0);
deviceContext->PSSetShader(m_pixelColorShader, NULL, 0);
}
bool SolidWireFrame::InitializeBlendState(ID3D11Device* device)
{
D3D11_BLEND_DESC blendStateDescription;
// Clear the blend state description.
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
// Create the blend state using the description.
HRESULT result = device->CreateBlendState(&blendStateDescription, &m_pBlendingState);
if (FAILED(result))
{
return false;
}
//ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
blendStateDescription.RenderTarget[0].BlendEnable = FALSE;
result = device->CreateBlendState(&blendStateDescription, &m_pnoColorBlendingState);
if (FAILED(result))
{
return false;
}
return true;
}
bool SolidWireFrame::InitializeDepthStencilState(ID3D11Device* device)
{
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
// Initialize the description of the stencil state.
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
// Set up the description of the stencil state.
depthStencilDesc.DepthEnable = TRUE;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
depthStencilDesc.StencilEnable = FALSE;
depthStencilDesc.StencilReadMask = 255;
depthStencilDesc.StencilWriteMask = 255;
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create the depth stencil state.
HRESULT result = device->CreateDepthStencilState(&depthStencilDesc, &m_pdepthLessEqualStencilState);
if (FAILED(result))
{
return false;
}
//ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
depthStencilDesc.DepthEnable = true;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
result = device->CreateDepthStencilState(&depthStencilDesc, &m_pdepthWriteLessStencilState);
if (FAILED(result))
{
return false;
}
return true;
}
bool SolidWireFrame::InitializeRaterizerState(ID3D11Device* device)
{
D3D11_RASTERIZER_DESC rasterizerDescription;
ZeroMemory(&rasterizerDescription, sizeof(D3D11_RASTERIZER_DESC));
rasterizerDescription.FillMode = D3D11_FILL_SOLID;
rasterizerDescription.CullMode = D3D11_CULL_NONE;
rasterizerDescription.DepthBias = FALSE;
rasterizerDescription.MultisampleEnable = TRUE;
rasterizerDescription.FrontCounterClockwise = FALSE;
rasterizerDescription.DepthBiasClamp = 0.000000000;
rasterizerDescription.SlopeScaledDepthBias = 0.000000000;
rasterizerDescription.DepthClipEnable = TRUE;
rasterizerDescription.ScissorEnable = FALSE;
rasterizerDescription.AntialiasedLineEnable = FALSE;
HRESULT hr = device->CreateRasterizerState(&rasterizerDescription, &m_pfillRasterizerState);
if (FAILED(hr))
return false;
return true;
}
bool SolidWireFrame::SetDepthStencilState(ID3D11DeviceContext* deviceContext, ID3D11DepthStencilState* depthStencilState)
{
deviceContext->OMSetDepthStencilState(depthStencilState, 0);
return false;
}
bool SolidWireFrame::SetRasterizerState(ID3D11DeviceContext* deviceContext, ID3D11RasterizerState* raterizerState)
{
deviceContext->RSSetState(raterizerState);
return false;
}
bool SolidWireFrame::SetBlendState(ID3D11DeviceContext* deviceContext, ID3D11BlendState* blendState)
{
float blendFactor[4];
// Setup the blend factor.
blendFactor[0] = 0.0f;
blendFactor[1] = 0.0f;
blendFactor[2] = 0.0f;
blendFactor[3] = 0.0f;
// Turn off the alpha blending.
deviceContext->OMSetBlendState(blendState, blendFactor, 0xffffffff);
return false;
}
bool SolidWireFrame::InitializeVertexShader(ID3D11Device* device)
{
// Create the vertex shader
HRESULT hr = device->CreateVertexShader(m_pwireVertexShader, sizeof(m_pwireVertexShader), NULL, &m_vertexShader);
if (FAILED(hr))
{
return false;
}
// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE(layout);
// Create the input layout
hr = device->CreateInputLayout(layout, numElements, m_pwireVertexShader, sizeof(m_pwireVertexShader), &m_vertexLayout);
if (FAILED(hr))
return false;
return true;
}
bool SolidWireFrame::InitializeGeometryShader(ID3D11Device* device)
{
// Create the geometry shader
HRESULT hr = device->CreateGeometryShader(m_pwireGeometryShader, sizeof(m_pwireGeometryShader), NULL, &m_geometrySolidWireShader);
if (FAILED(hr))
return false;
hr = device->CreateGeometryShader(m_pgeometryShader, sizeof(m_pgeometryShader), NULL, &m_geometryShader);
if (FAILED(hr))
return false;
return true;
}
bool SolidWireFrame::InitializePixelShader(ID3D11Device* device)
{
// Create the pixel shader
HRESULT hr = device->CreatePixelShader(m_pwirePixelShader, sizeof(m_pwirePixelShader), NULL, &m_pixelSolidWireShader);
if (FAILED(hr))
return false;
hr = device->CreatePixelShader(m_pcolorPixelShader, sizeof(m_pcolorPixelShader), NULL, &m_pixelColorShader);
if (FAILED(hr))
return false;
return true;
}
}
now in my application, at the end of Initializing the Device and Context etc. i call.
SolidWireFrame* solidWireFrame = new SolidWireFrame();
solidWireFrame->Init(m_pd3dDevice.Get());
m_solidWireFrame.reset(solidWireFrame);
and my render loop.
//m_solidWireFrame->ApplyDepthAndSolid(m_pImmediateContext);
//m_solidWireFrame->ApplyDepthOnly(m_pImmediateContext);
//m_solidWireFrame->ApplySolidOnly(m_pImmediateContext);
/*for (it_drawingData iterator = dd.begin(); iterator != dd.end(); iterator++)
{
DrawingData *drawingData = iterator->second;
if (drawingData->IsRendered)
{
m_pImmediateContext->IASetVertexBuffers(0, 1, &drawingData->VertexBuffer, &stride, &offset);
m_pImmediateContext->IASetIndexBuffer(drawingData->IndexBuffer, DXGI_FORMAT_R16_UINT, 0);
m_pImmediateContext->DrawIndexed(drawingData->IndexData.size(), 0, 0);
}
}
//not sure if i should call this between renders?
m_pdesignerSwapChain->Present(0, 0);*/
m_solidWireFrame->ApplySolidWirePattern(m_pImmediateContext);
for (it_drawingData iterator = dd.begin(); iterator != dd.end(); iterator++)
{
DrawingData *drawingData = iterator->second;
if (drawingData->IsRendered)
{
m_pImmediateContext->IASetVertexBuffers(0, 1, &drawingData->VertexBuffer, &stride, &offset);
m_pImmediateContext->IASetIndexBuffer(drawingData->IndexBuffer, DXGI_FORMAT_R16_UINT, 0);
m_pImmediateContext->DrawIndexed(drawingData->IndexData.size(), 0, 0);
}
}
Fixed it.
I was not setting the world, view, projection constant buffer for the wireframe vs.
I have searched for a way to retrieve information from a digital signed PE file. I need the publisher, publisher link , issuer name and subject name. I need winapi / c / c++ code (functions) and i need a fast method , i don't need to check if the signature is valid or not.
Here is code that I wrote for a project of mine that will do this. It returns the details in a struct of type NSIGINFO. Feel free to use it - no attribution necessary, but I would appreciate it if you would leave the copyright intact.
If there's any functions missing (I had to consolidate things from a couple of different places so I may have missed something) please let me know and I'll make the necessary tweaks.
Let me know how this works for you. Good luck.
The header file, NAuthenticode.h:
// NAuthenticode.h: Functions for checking signatures in files
//
// Copyright (c) 2008-2012, Nikolaos D. Bougalis <nikb#bougalis.net>
#ifndef B82FBB5B_C0F8_43A5_9A31_619BB690706C
#define B82FBB5B_C0F8_43A5_9A31_619BB690706C
#include <wintrust.h>
#include <softpub.h>
#include <imagehlp.h>
struct NSIGINFO
{
LONG lValidationResult;
LPTSTR lpszPublisher;
LPTSTR lpszPublisherEmail;
LPTSTR lpszPublisherUrl;
LPTSTR lpszAuthority;
LPTSTR lpszFriendlyName;
LPTSTR lpszProgramName;
LPTSTR lpszPublisherLink;
LPTSTR lpszMoreInfoLink;
LPTSTR lpszSignature;
LPTSTR lpszSerial;
BOOL bHasSigTime;
SYSTEMTIME stSigTime;
};
VOID NCertFreeSigInfo(NSIGINFO *pSigInfo);
BOOL NVerifyFileSignature(LPCTSTR lpszFileName, NSIGINFO *pSigInfo, HANDLE hHandle = INVALID_HANDLE_VALUE);
BOOL NCertGetNameString(PCCERT_CONTEXT pCertContext, DWORD dwType,
DWORD dwFlags, LPTSTR *lpszNameString);
BOOL NCheckFileCertificates(HANDLE hFile,
VOID (*pCallback)(PCCERT_CONTEXT, LPVOID), PVOID pParam);
#endif
The implementation, NAuthenticode.cpp:
// NAuthenticode.cpp: Various routines related to validating file signatures
//
// Copyright (c) 2008-2012, Nikolaos D. Bougalis <nikb#bougalis.net>
#include "stdafx.h"
#include "NAuthenticode.h"
//////////////////////////////////////////////////////////////////////////
#pragma comment(lib, "crypt32")
#pragma comment(lib, "imagehlp")
#pragma comment(lib, "wintrust")
//////////////////////////////////////////////////////////////////////////
#define SIG_ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
//////////////////////////////////////////////////////////////////////////
// Some utility functions
LPVOID NHeapAlloc(SIZE_T dwBytes)
{
if(dwBytes == 0)
return NULL;
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytes);
}
//////////////////////////////////////////////////////////////////////////
LPVOID NHeapFree(LPVOID lpMem)
{
if(lpMem != NULL)
HeapFree(GetProcessHeap(), 0, lpMem);
return NULL;
}
//////////////////////////////////////////////////////////////////////////
LPSTR NConvertW2A(LPCWSTR lpszString, int nLen, UINT nCodePage)
{
ASSERT(lpszString != NULL);
int ret = WideCharToMultiByte(nCodePage, 0, lpszString, nLen, NULL, 0, NULL, NULL);
if(ret <= 0)
return NULL;
LPSTR lpszOutString = (LPSTR)NHeapAlloc((ret + 1) * sizeof(CHAR));
if(lpszOutString == NULL)
return NULL;
ret = WideCharToMultiByte(nCodePage, 0, lpszString, nLen, lpszOutString, ret, NULL, NULL);
if(ret <= 0)
lpszOutString = (LPSTR)NHeapFree(lpszOutString);
return lpszOutString;
}
//////////////////////////////////////////////////////////////////////////
LPWSTR NDupString(LPCWSTR lpszString, int nLen)
{
if(nLen == -1)
nLen = (int)wcslen(lpszString);
LPWSTR lpszOutString = (LPWSTR)NHeapAlloc((2 + nLen) * sizeof(WCHAR));
if((lpszOutString != NULL) && (nLen != 0))
wcsncpy(lpszOutString, lpszString, nLen + 1);
return lpszOutString;
}
//////////////////////////////////////////////////////////////////////////
LPTSTR NConvertW2T(LPCWSTR lpszString, int nLen, UINT nCodePage)
{
ASSERT(lpszString != NULL);
#ifndef UNICODE
return (LPTSTR)NConvertW2A(lpszString, nLen, nCodePage);
#else
return (LPTSTR)NDupString(lpszString, nLen);
#endif
}
//////////////////////////////////////////////////////////////////////////
LPWSTR NConvertA2W(LPCSTR lpszString, int nLen, UINT nCodePage)
{
ASSERT(lpszString != NULL);
int ret = MultiByteToWideChar(nCodePage, 0, lpszString, nLen, NULL, 0);
if(ret <= 0)
return NULL;
LPWSTR lpszOutString = (LPWSTR)NHeapAlloc((ret + 1) * sizeof(WCHAR));
if(lpszOutString == NULL)
return NULL;
ret = MultiByteToWideChar(nCodePage, 0, lpszString, nLen, lpszOutString, ret);
if(ret <= 0)
lpszOutString = (LPWSTR)NHeapFree(lpszOutString);
return lpszOutString;
}
//////////////////////////////////////////////////////////////////////////
LPWSTR NConvertT2W(LPCTSTR lpszString, int nLen, UINT nCodePage)
{
ASSERT(lpszString != NULL);
#ifndef UNICODE
return NConvertA2W((LPCSTR)lpszString, nLen, nCodePage);
#else
return NDupString((LPWSTR)lpszString, nLen);
#endif
}
//////////////////////////////////////////////////////////////////////////
VOID NCertFreeSigInfo(NSIGINFO *pSigInfo)
{
if(pSigInfo == NULL)
return;
__try
{ // Be extra careful
if(pSigInfo->lpszPublisher)
pSigInfo->lpszPublisher = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszPublisherEmail)
pSigInfo->lpszPublisherEmail = (LPTSTR)NHeapFree(pSigInfo->lpszPublisherEmail);
if(pSigInfo->lpszPublisherUrl)
pSigInfo->lpszPublisherUrl = (LPTSTR)NHeapFree(pSigInfo->lpszPublisherUrl);
if(pSigInfo->lpszAuthority)
pSigInfo->lpszAuthority = (LPTSTR)NHeapFree(pSigInfo->lpszAuthority);
if(pSigInfo->lpszProgramName)
pSigInfo->lpszProgramName = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszPublisherLink)
pSigInfo->lpszPublisherLink = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszMoreInfoLink)
pSigInfo->lpszMoreInfoLink = (LPTSTR)NHeapFree(pSigInfo->lpszMoreInfoLink);
if(pSigInfo->lpszSignature)
pSigInfo->lpszSignature = (LPTSTR)NHeapFree(pSigInfo->lpszSignature);
if(pSigInfo->lpszSerial)
pSigInfo->lpszSerial = (LPTSTR)NHeapFree(pSigInfo->lpszSerial);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
//////////////////////////////////////////////////////////////////////////
static BOOL NCertGetNameString(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, LPTSTR *lpszNameString)
{
if(pCertContext == NULL)
return FALSE;
DWORD dwData = CertGetNameString(pCertContext, dwType, 0, NULL, NULL, 0);
if(dwData == 0)
return FALSE;
*lpszNameString = (LPTSTR)NHeapAlloc((dwData + 1) * sizeof(TCHAR));
if(*lpszNameString == NULL)
return FALSE;
dwData = CertGetNameString(pCertContext, dwType, dwFlags, NULL, *lpszNameString, dwData);
if(dwData == 0)
{
NHeapFree(*lpszNameString);
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
static BOOL NCryptDecodeObject(__in LPCSTR lpszObjectId, __in_bcount(cbEncoded) const BYTE *pbEncoded, __in DWORD cbEncoded,
__inout DWORD &dwBuffer, __out void *pBuffer = NULL, __in DWORD dwFlags = 0)
{
if(((pBuffer == NULL) && (dwBuffer != 0)) || ((dwBuffer == 0) && (pBuffer != NULL)))
{ // What? You're passing a NULL pointer an a non-zero size? You so crazy!!!!
ASSERT(FALSE);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return CryptDecodeObject(SIG_ENCODING, lpszObjectId, pbEncoded, cbEncoded, dwFlags, pBuffer, &dwBuffer);
}
//////////////////////////////////////////////////////////////////////////
static BOOL NCryptDecodeObject(__in LPCSTR lpszObjectId, __in PCRYPT_ATTR_BLOB pObject,
__inout DWORD &dwBuffer, __out void *pBuffer = NULL, __in DWORD dwFlags = 0)
{
if((pObject == NULL) || ((dwBuffer == 0) && (pBuffer != NULL)) || ((dwBuffer != 0) && (pBuffer == NULL)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return CryptDecodeObject(SIG_ENCODING, lpszObjectId, pObject->pbData, pObject->cbData, dwFlags, pBuffer, &dwBuffer);
}
//////////////////////////////////////////////////////////////////////////
static BOOL WGetSignTimestamp(PCRYPT_ATTRIBUTES pAttributes, SYSTEMTIME &stTime, LPCSTR lpszObjId)
{
if((pAttributes == NULL) || (pAttributes->cAttr == 0) || (lpszObjId == NULL) || (*lpszObjId == 0))
return FALSE;
for(DWORD dwAttr = 0; dwAttr < pAttributes->cAttr; dwAttr++)
{
if(strcmp(lpszObjId, pAttributes->rgAttr[dwAttr].pszObjId) == 0)
{
DWORD dwSize = sizeof(FILETIME);
FILETIME ftCert;
if(NCryptDecodeObject(lpszObjId, &pAttributes->rgAttr[dwAttr].rgValue[0], dwSize, (PVOID)&ftCert))
{
FILETIME ftLocal;
if(FileTimeToLocalFileTime(&ftCert, &ftLocal) && FileTimeToSystemTime(&ftLocal, &stTime))
return TRUE;
}
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
static BOOL NVerifyFileSignatureWorker(LPWSTR lpszFileName, WINTRUST_DATA &wtData, NSIGINFO *pSigInfo)
{
if(pSigInfo != NULL)
memset(pSigInfo, 0, sizeof(NSIGINFO));
GUID guidAction = WINTRUST_ACTION_GENERIC_VERIFY_V2;
BOOL bVerified = FALSE;
LONG lRet = WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &guidAction, &wtData);
if(lRet != 0)
{
if(pSigInfo != NULL)
pSigInfo->lValidationResult = lRet;
return FALSE;
}
if(pSigInfo == NULL)
return TRUE;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
if(!CryptQueryObject(CERT_QUERY_OBJECT_FILE, lpszFileName, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL, &hStore, &hMsg, NULL))
return FALSE;
PCMSG_SIGNER_INFO pSignerInfo = NULL, pCounterSignerInfo = NULL;
DWORD dwSignerInfo = 0, dwCounterSignerInfo = 0;
if(CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo) && (dwSignerInfo != 0))
pSignerInfo = (PCMSG_SIGNER_INFO)NHeapAlloc(dwSignerInfo);
if((pSignerInfo != NULL) && CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo))
{
for(DWORD dwAttr = 0; dwAttr < pSignerInfo->AuthAttrs.cAttr; dwAttr++)
{
if((strcmp(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[dwAttr].pszObjId) != 0))
continue;
PSPC_SP_OPUS_INFO pOpus = NULL;
DWORD dwData = 0;
if(NCryptDecodeObject(SPC_SP_OPUS_INFO_OBJID, &pSignerInfo->AuthAttrs.rgAttr[dwAttr].rgValue[0], dwData) && (dwData != 0))
pOpus = (PSPC_SP_OPUS_INFO)NHeapAlloc(dwData);
if((pOpus != NULL) && NCryptDecodeObject(SPC_SP_OPUS_INFO_OBJID, &pSignerInfo->AuthAttrs.rgAttr[dwAttr].rgValue[0], dwData, (PVOID)pOpus))
{
pSigInfo->lpszProgramName = NConvertW2T(pOpus->pwszProgramName);
if(pOpus->pPublisherInfo != NULL)
{
switch(pOpus->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pSigInfo->lpszPublisherLink = NConvertW2T(pOpus->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pSigInfo->lpszPublisherLink = NConvertW2T(pOpus->pPublisherInfo->pwszFile);
break;
}
}
if(pOpus->pMoreInfo != NULL)
{
switch (pOpus->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pSigInfo->lpszMoreInfoLink = NConvertW2T(pOpus->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pSigInfo->lpszMoreInfoLink = NConvertW2T(pOpus->pMoreInfo->pwszFile);
break;
}
}
}
if(pOpus != NULL)
NHeapFree(pOpus);
break;
}
CERT_INFO ci;
ci.Issuer = pSignerInfo->Issuer;
ci.SerialNumber = pSignerInfo->SerialNumber;
PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hStore, SIG_ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)&ci, NULL);
if(pCertContext != NULL)
{
if(pCertContext->pCertInfo->SerialNumber.cbData != 0)
{
pSigInfo->lpszSerial = (LPTSTR)NHeapAlloc(((pCertContext->pCertInfo->SerialNumber.cbData * 2) + 1) * sizeof(TCHAR));
if(pSigInfo->lpszSerial != NULL)
{
LPTSTR lpszPointer = pSigInfo->lpszSerial;
for(DWORD dwCount = pCertContext->pCertInfo->SerialNumber.cbData; dwCount != 0; dwCount--)
lpszPointer += _stprintf(lpszPointer, _T("%02X"), pCertContext->pCertInfo->SerialNumber.pbData[dwCount - 1]);
}
}
if(!NCertGetNameString(pCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, &pSigInfo->lpszFriendlyName))
pSigInfo->lpszFriendlyName = NULL;
if(!NCertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, &pSigInfo->lpszAuthority))
pSigInfo->lpszAuthority = NULL;
if(!NCertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &pSigInfo->lpszPublisher))
pSigInfo->lpszPublisher = NULL;
if(!NCertGetNameString(pCertContext, CERT_NAME_URL_TYPE, 0, &pSigInfo->lpszPublisherUrl))
pSigInfo->lpszPublisherUrl = NULL;
if(!NCertGetNameString(pCertContext, CERT_NAME_EMAIL_TYPE, 0, &pSigInfo->lpszPublisherEmail))
pSigInfo->lpszPublisherEmail = NULL;
CertFreeCertificateContext(pCertContext);
}
for(DWORD dwAttr = 0, dwData; dwAttr < pSignerInfo->AuthAttrs.cAttr; dwAttr++)
{
if((strcmp(szOID_RSA_signingTime, pSignerInfo->AuthAttrs.rgAttr[dwAttr].pszObjId) == 0) && (pSignerInfo->AuthAttrs.rgAttr[dwAttr].cValue != 0))
{
FILETIME ftCert;
dwData = sizeof(FILETIME);
if(NCryptDecodeObject(szOID_RSA_signingTime, &pSignerInfo->AuthAttrs.rgAttr[dwAttr].rgValue[0], dwData, (PVOID)&ftCert))
{
FILETIME ftLocal;
if(!FileTimeToLocalFileTime(&ftCert, &ftLocal))
{
if(!FileTimeToSystemTime(&ftLocal, &pSigInfo->stSigTime))
memset(&pSigInfo->stSigTime, 0, sizeof(SYSTEMTIME));
}
}
}
}
for(DWORD dwAttr = 0; dwAttr < pSignerInfo->UnauthAttrs.cAttr; dwAttr++)
{
if(strcmp(pSignerInfo->UnauthAttrs.rgAttr[dwAttr].pszObjId, szOID_RSA_counterSign) == 0)
{
if(NCryptDecodeObject(PKCS7_SIGNER_INFO, &pSignerInfo->UnauthAttrs.rgAttr[dwAttr].rgValue[0], dwCounterSignerInfo) && (dwCounterSignerInfo != 0))
pCounterSignerInfo = (PCMSG_SIGNER_INFO)NHeapAlloc(dwCounterSignerInfo);
if((pCounterSignerInfo != NULL) && !NCryptDecodeObject(PKCS7_SIGNER_INFO, &pSignerInfo->UnauthAttrs.rgAttr[dwAttr].rgValue[0], dwCounterSignerInfo, pCounterSignerInfo))
pCounterSignerInfo = (PCMSG_SIGNER_INFO)NHeapFree(pCounterSignerInfo);
break;
}
}
if(pCounterSignerInfo != NULL)
{
pSigInfo->bHasSigTime = WGetSignTimestamp(&pCounterSignerInfo->AuthAttrs, pSigInfo->stSigTime, szOID_RSA_signingTime);
if(!pSigInfo->bHasSigTime)
memset(&pSigInfo->stSigTime, 0, sizeof(SYSTEMTIME));
}
}
if(pSignerInfo != NULL)
NHeapFree(pSignerInfo);
if(pCounterSignerInfo != NULL)
NHeapFree(pCounterSignerInfo);
if(hStore != NULL)
CertCloseStore(hStore, 0);
if(hMsg != NULL)
CryptMsgClose(hMsg);
return TRUE;
}
//////////////////////////////////////////////////////////////////////////
BOOL NVerifyFileSignature(LPCTSTR lpszFileName, NSIGINFO *pSigInfo, HANDLE hHandle)
{
if(pSigInfo != NULL)
memset(pSigInfo, 0, sizeof(NSIGINFO));
if(lpszFileName == NULL)
return FALSE;
if((lpszFileName[0] != 0) && (_tcsnicmp(lpszFileName, _T("\\??\\"), 4) == 0))
lpszFileName += 4;
if(lpszFileName[0] == 0)
return FALSE;
LPWSTR lpwszFileName = NConvertT2W(lpszFileName);
if(lpwszFileName == NULL)
return FALSE;
BOOL bOK = FALSE;
__try
{ // be very careful...
WINTRUST_FILE_INFO wtFileInfo;
memset(&wtFileInfo, 0, sizeof(WINTRUST_FILE_INFO));
wtFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
wtFileInfo.pcwszFilePath = lpwszFileName;
if(hHandle != INVALID_HANDLE_VALUE)
wtFileInfo.hFile = hHandle;
WINTRUST_DATA wtData;
memset(&wtData, 0, sizeof(WINTRUST_DATA));
wtData.cbStruct = sizeof(WINTRUST_DATA);
wtData.dwUIChoice = WTD_UI_NONE;
wtData.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
wtData.dwUnionChoice = WTD_CHOICE_FILE;
wtData.pFile = &wtFileInfo;
if(NVerifyFileSignatureWorker(lpwszFileName, wtData, pSigInfo))
bOK = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if(pSigInfo != NULL)
{
if(pSigInfo->lpszPublisher)
pSigInfo->lpszPublisher = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszAuthority)
pSigInfo->lpszAuthority = (LPTSTR)NHeapFree(pSigInfo->lpszAuthority);
if(pSigInfo->lpszProgramName)
pSigInfo->lpszProgramName = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszPublisherLink)
pSigInfo->lpszPublisherLink = (LPTSTR)NHeapFree(pSigInfo->lpszPublisher);
if(pSigInfo->lpszMoreInfoLink)
pSigInfo->lpszMoreInfoLink = (LPTSTR)NHeapFree(pSigInfo->lpszMoreInfoLink);
if(pSigInfo->lpszSignature)
pSigInfo->lpszSignature = (LPTSTR)NHeapFree(pSigInfo->lpszSignature);
if(pSigInfo->lpszSerial)
pSigInfo->lpszSerial = (LPTSTR)NHeapFree(pSigInfo->lpszSerial);
}
bOK = FALSE;
}
NHeapFree(lpwszFileName);
return bOK;
}
//////////////////////////////////////////////////////////////////////////
BOOL NCheckFileCertificates(HANDLE hFile, VOID (*pCallback)(PCCERT_CONTEXT, LPVOID), PVOID pParam)
{
DWORD dwCerts = 0;
if(!ImageEnumerateCertificates(hFile, CERT_SECTION_TYPE_ANY, &dwCerts, NULL, 0))
return FALSE;
for(DWORD dwCount = 0; dwCount < dwCerts; dwCount++)
{
WIN_CERTIFICATE wcHdr;
memset(&wcHdr, 0, sizeof(WIN_CERTIFICATE));
wcHdr.dwLength = 0;
wcHdr.wRevision = WIN_CERT_REVISION_1_0;
if(!ImageGetCertificateHeader(hFile, dwCount, &wcHdr))
return FALSE;
DWORD dwLen = sizeof(WIN_CERTIFICATE) + wcHdr.dwLength;
WIN_CERTIFICATE *pWinCert = (WIN_CERTIFICATE *)NHeapAlloc(dwLen);
if(pWinCert == NULL)
return FALSE;
if(!ImageGetCertificateData(hFile, dwCount, pWinCert, &dwLen))
{ // problem getting certificate, return failure
NHeapFree(pWinCert);
return FALSE;
}
// extract the PKCS7 signed data
CRYPT_VERIFY_MESSAGE_PARA cvmp;
memset(&cvmp, 0, sizeof(CRYPT_VERIFY_MESSAGE_PARA));
cvmp.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
cvmp.dwMsgAndCertEncodingType = SIG_ENCODING;
PCCERT_CONTEXT pCertContext = NULL;
if(!CryptVerifyMessageSignature(&cvmp, dwCount, pWinCert->bCertificate, pWinCert->dwLength, NULL, NULL, &pCertContext))
{
NHeapFree(pWinCert);
return FALSE;
}
// Now, pass this context on to our callback function (if any)
if(pCallback != NULL)
pCallback(pCertContext, pParam);
if(!CertFreeCertificateContext(pCertContext))
{
NHeapFree(pWinCert);
return FALSE;
}
NHeapFree(pWinCert);
}
return TRUE;
}
Microsoft provides a way to do it in this support link: How To Get Information from Authenticode Signed Executables
You can use the WinVerifyTrust() API to verify an Authenticode signed
executable.
Although a signature is verified, a program may also have to do the
following:
Determine the details of the certificate that signed the
executable.
Determine the date and time that the file was time
stamped.
Retrieve the URL link associated with the file.
Retrieve the timestamp certificate.
This article demonstrates how to use
CryptQueryObject() API to retrieve detailed information from an
Authenticode signed executable.