Problem with MSMQ configuration or code i've implemented??
I've written windows service code (win32 C++ ) in which i am sending a log to the local private queue.This code is working fine if I execute that in 32-bit environment (either windows7/8/vista). But that same code if I build for x64 OS and if I execute MQSendMessage() failed with MQ_ERROR_INVALID_PARAMETER (0xC00E0006). What could be the problem.??? Please help me out in this regard.Thanks in advance..
I've tried by changing the NUMBEROFPROPERTIES from 3-7 in x-64 windows 7 system. But still the problem remains same. what to do to avoid this..
Here is my sample code
#define ClientQueue L".\\Private$\\TestQueue"
#define LogMsgLable L"TestLOG"
#define MIN_PRIVATE_QUEUE_NAME_LENGTH 55
DWORD MSMQSendMessage()
{
//Define the required constants and variables.
const int NUMBEROFPROPERTIES = 7; // Number of properties
DWORD cPropId = 0; // Property counter
HRESULT hr = MQ_OK; // Return code
HANDLE hQueue = NULL; // Queue handle
//Define an MQMSGPROPS structure.
MQMSGPROPS msgProps;
MSGPROPID aMsgPropId[NUMBEROFPROPERTIES] = {0};
MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES] = {0};
HRESULT aMsgStatus[NUMBEROFPROPERTIES] = {0};
// Specify the message properties to be sent.
aMsgPropId[cPropId] = PROPID_M_LABEL; // Property ID
aMsgPropVar[cPropId].vt = VT_LPWSTR; // Type indicator
aMsgPropVar[cPropId].pwszVal = L"ADCLOG"; // The message label
cPropId++;
// Specifying the storage of messages in the harddisk
// setting the message properties as recoverable
aMsgPropId[cPropId] = PROPID_M_DELIVERY;
aMsgPropVar[cPropId].vt = VT_UI1;
aMsgPropVar[cPropId].bVal = MQMSG_DELIVERY_RECOVERABLE;
cPropId++;
aMsgPropId[cPropId] = PROPID_M_ACKNOWLEDGE; // Property ID
aMsgPropVar[cPropId].vt = VT_UI1; // Type indicator
aMsgPropVar[cPropId].bVal = MQMSG_ACKNOWLEDGMENT_FULL_RECEIVE;
cPropId++;
// we need to set the size of the message
// if we dont set it, takes 4MB as default message size
// to set the size of it we have ---> PROPID_M_BODY
ULONG ulBufferSize = 15;
char *lLog_msg = NULL;
lLog_msg = ( char*)GlobalAlloc( GPTR, 15);
ZeroMemory( lLog_msg, 15) ;
strcpy(lLog_msg, "HelloWorld");
aMsgPropId[cPropId] = PROPID_M_BODY; // Property ID
aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1; // Type indicator
aMsgPropVar[cPropId].caub.pElems = (UCHAR *)lLog_msg; // Body buffer
aMsgPropVar[cPropId].caub.cElems = ulBufferSize; // Buffer size
cPropId++;
//here we should not put VT_NULL in type as defined with VT_UI4.........
aMsgPropId[cPropId] = PROPID_M_BODY_TYPE; // Property ID
aMsgPropVar[cPropId].vt = VT_UI4; // Type indicator
cPropId++;
// Initialize the MQMSGPROPS structure.
msgProps.cProp = cPropId;
msgProps.aPropID = aMsgPropId;
msgProps.aPropVar = aMsgPropVar;
msgProps.aStatus = aMsgStatus;
// Create a direct format name for the queue.
WCHAR *gFormatName = NULL;
DWORD dwBufferLength = 0;
dwBufferLength = MIN_PRIVATE_QUEUE_NAME_LENGTH; //Private queue format name buffer size atleast 54
gFormatName = (WCHAR *)malloc( dwBufferLength*sizeof( WCHAR ));
if (gFormatName == NULL)
{
printf( "malloc", 0, NULL );
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
SecureZeroMemory( gFormatName, dwBufferLength*sizeof(WCHAR) );
hr = MQPathNameToFormatName( ClientQueue,
gFormatName,
&dwBufferLength );
if (FAILED( hr ))
{
if( hr == MQ_ERROR_FORMATNAME_BUFFER_TOO_SMALL )
{
if (gFormatName != NULL)
{
gFormatName = (WCHAR *)realloc( gFormatName, dwBufferLength*sizeof( WCHAR ));
if (gFormatName == NULL)
{
printf( "realloc failed\n");
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
}
SecureZeroMemory( gFormatName, dwBufferLength*sizeof( WCHAR ));
hr = MQPathNameToFormatName( ClientQueue,
gFormatName,
&dwBufferLength );
if(FAILED( hr ))
{
printf( L"MQPathNameToFormatName2 failed:%x\n", hr);
return hr;
}
}
else
{
printf("MQPathNameToFormatName failed:%x\n", hr);
return hr;
}
}
// Call MQOpenQueue to open the queue with send access.
hr = MQOpenQueue(
gFormatName, // Format name of the queue
MQ_SEND_ACCESS, // Access mode
MQ_DENY_NONE, // Share mode
&hQueue // OUT: Queue handle
);
if ( FAILED( hr ))
{
printf("MQOpenQueue failed:%x\n", hr);
goto ret;
//goto cleanup;
}
if( gFormatName )
free( gFormatName );
// Call MQSendMessage to send the message to the queue.
hr = MQSendMessage(
hQueue, // Queue handle
&msgProps, // Message property structure
NULL // Not in a transaction
);
if (FAILED(hr))
{
printf( "MQSendMessage failed:%x\n", hr );
MQCloseQueue( hQueue );
goto ret;
}
//Call MQCloseQueue to close the queue.
hr = MQCloseQueue(hQueue);
if(hr != 0)
{
printf("MQCloseQueue failed:%x",hr);
//goto cleanup;
goto ret;
}ret:
if( lLog_msg )
{
GlobalFree( lLog_msg );
lLog_msg = NULL;
}
return hr;
}
Your code works on 32-bit Windows purely by chance. Take a look at this:
ULONG ulBufferSize = sizeof( 15);
char *lLog_msg = NULL;
lLog_msg = ( char*)GlobalAlloc( GPTR, sizeof( 15));
ZeroMemory( lLog_msg, sizeof( 15)) ;
strcpy(lLog_msg, "HelloWorld");
You seem to misunderstand what the sizeof operator does. It is a compile time operator that replaces its argument with the size of that argument. In this case, the compiler replaces sizeof(15) with the number 4. Why? Because a literal constant like 15 occupies 4 bytes on a 64-bit machine. So in the code above you are allocating 4 bytes of memory and then copying 11 bytes into it, thereby corrupting memory.
To fix this, simply remove sizeof. The code above should look like this:
ULONG ulBufferSize = 15;
char *lLog_msg = NULL; // this is pointless since you set it in the next line
lLog_msg = ( char*)GlobalAlloc( GPTR, ulBufferSize);
ZeroMemory( lLog_msg, ulBufferSize) ;
strcpy(lLog_msg, "HelloWorld");
Related
In order to write to HD at max. performance I'm using overlapped I/O.
It works.
Upon acquiring 4MB of data (from sensor) I'm writing it to disk.
Then, upon getting the next 4MB I first ask if the previous writing completed.
How can I know what is the optimal block size (4MB ?) that is best for my disk ?
// AsyncFile.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "AsyncFile.h"
/****************************************************************************/
CAsyncFile::CAsyncFile()
{
}
/****************************************************************************/
CAsyncFile::~CAsyncFile()
{
}
/****************************************************************************/
int CAsyncFile::OpenFile(char *pcFileName,
bool bAsync, // Whether async read/write is required
bool bWrite) // True is file is used for writing to
{
DWORD dwAsyncMask = bAsync ? (FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING) : 0;
DWORD dwCreation = bWrite ? CREATE_ALWAYS : OPEN_EXISTING;
DWORD dwAccess = bWrite ? GENERIC_WRITE : GENERIC_READ;
DWORD dwShareMode = bWrite ? FILE_SHARE_READ : FILE_SHARE_WRITE;
if (strlen(pcFileName) < sizeof(m_cFileName))
strcpy_s(m_cFileName, 256, pcFileName);
else
m_cFileName[0] = 0; // NULL (error - file name is too long)
// Calling openFile() sets a valid value to the file handle
m_hFileHandle = INVALID_HANDLE_VALUE;
// Auto reset (manual reset=false), init state = false, no name
m_hIoCompleted = CreateEvent(NULL, FALSE, FALSE, NULL);
// Init OVERLAPPED structure, for async read
m_tOverlapped.Offset = 0;
m_tOverlapped.OffsetHigh = 0;
m_tOverlapped.hEvent = m_hIoCompleted;
m_Event = m_tOverlapped.hEvent;
if (m_hFileHandle != INVALID_HANDLE_VALUE)
{
// File is already openned; check open mode
if ((bAsync == m_bAsync) && (bWrite == m_bWrite))
return (ASYNCFILE_OK);
// File is already openned, but in other mode; Should close file
// before using it again
return ASYNCFILE_FILE_IS_NOT_IN_WRITE_MODE;
}
m_hFileHandle =
CreateFile((LPCTSTR)m_cFileName,
dwAccess, // Open for read or write
dwShareMode, //
NULL, // No SECURITY_ATTRBUTES
dwCreation, // Open exisiting file (if read) \ create new (if write)
dwAsyncMask, // For asynchronous operations, for maximum asynchronous performence
0);
if (m_hFileHandle == INVALID_HANDLE_VALUE)
{
DWORD dwError = GetLastError();
return ASYNCFILE_FAILED_TO_OPEN_FILE;
}
//In case file opened for reading, get its size
if (bWrite == false)
{
GetFileSizeEx(m_hFileHandle, &m_FileSize);
}
// Save open mode
m_bAsync = bAsync;
m_bWrite = bWrite;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::CloseFile()
{
//BOOL Status;
if (!CloseHandle(m_hFileHandle))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
if (!CloseHandle(m_hIoCompleted))
return ASYNCFILE_FAILED_TO_CLOSE_FILE;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncRead(void* pBuffer,
DWORD dwReadSize,
bool* pbEof)
{
*pbEof = false; // By default, EOF is false
int iError;
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return (false);
if (!ReadFile(m_hFileHandle,
pBuffer,
dwReadSize,
NULL, // actual bytes read is not valid now
&m_tOverlapped))
{
if ((iError = GetLastError()) == ERROR_HANDLE_EOF)
{
*pbEof = true;
return ASYNCFILE_OK;
}
else if (!(m_bAsync && (iError == ERROR_IO_PENDING)))
{
return ASYNCFILE_START_READ_FAILED;
}
}
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::WaitAsyncOperationEnd(DWORD* pdwActualBytesTransferred)
{
if (m_hFileHandle == INVALID_HANDLE_VALUE)
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
// Wait for read operation to complete
if (!GetOverlappedResult(m_hFileHandle,
&m_tOverlapped,
pdwActualBytesTransferred,
true))
return ASYNCFILE_WAIT_FOR_COMPLETION_FAILED;
return ASYNCFILE_OK;
}
/****************************************************************************/
int CAsyncFile::StartAsyncWrite(void* pSrcBuf,
DWORD dwSize) // In bytes
{
int iError;
if (!WriteFile(m_hFileHandle,
pSrcBuf,
dwSize,
NULL, // actual bytes written is not valid now
&m_tOverlapped))
{
iError = GetLastError();
if (iError != ERROR_IO_PENDING)
return ASYNCFILE_START_WRITE_FAILED;
}
return ASYNCFILE_OK;
}
/****************************************************************************/
void CAsyncFile::SetFilePosition(UINT64 Position)
{
m_tOverlapped.Offset = Position & 0xFFFFFFFF;
m_tOverlapped.OffsetHigh = Position >> 32;
}
/****************************************************************************/
UINT64 CAsyncFile::GetFilePosition()
{
UINT64 Position;
Position = (m_tOverlapped.Offset) | ((UINT64)m_tOverlapped.OffsetHigh << 32);
return (Position);
}
/****************************************************************************/
UINT64 CAsyncFile::GetFileSize()
{
return (m_FileSize.QuadPart);
}
Well it depends on the average size of your files as well. If your file sizes are constantly ranging near 7 to 8 MB, then there would be some benefit in increasing the buffer size to 8192KB. How old is the drive? How often have you used it, many other factors come into play. We are able to learn more about this topic from an excellent piece of software called FastCopy. Hope this helps.
I am building a credential provider which works same like windows smart card credential provider i.e this works only with domain accounts. I am facing an issue when passing the credentials to Negotiate SSP and I am using microsoft base smart card crypto provider as CSP. I am getting The parameter is incorrect error on lock screen after entering pin.
GetSerialization
HRESULT CCredential::GetSerialization(
CREDENTIAL_PROVIDER_GET_SERIALIZATION_RESPONSE* pcpgsr,
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcpcs,
PWSTR* ppwszOptionalStatusText,
CREDENTIAL_PROVIDER_STATUS_ICON* pcpsiOptionalStatusIcon
)
{
UNREFERENCED_PARAMETER(ppwszOptionalStatusText);
UNREFERENCED_PARAMETER(pcpsiOptionalStatusIcon);
HRESULT hr;
WCHAR dmz[244] = L"demodomain";
PWSTR pwzProtectedPin;
hr = ProtectIfNecessaryAndCopyPassword(_rgFieldStrings[SFI_PIN], _cpus, _dwFlags, &pwzProtectedPin);
if (SUCCEEDED(hr))
{
KERB_CERTIFICATE_UNLOCK_LOGON kiul;
// Initialize kiul with weak references to our credential.
hr = UnlockLogonInit(dmz, _rgFieldStrings[SFI_USERNAME], pwzProtectedPin, _cpus, &kiul);
if (SUCCEEDED(hr))
{
PBASE_SMARTCARD_CSP_INFO pCspInfo = _pContainer->GetCSPInfo();
if (pCspInfo)
{
CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION* pcp;
hr = UnlockLogonPack(kiul, pCspInfo, &pcpcs->rgbSerialization, &pcpcs->cbSerialization);
_pContainer->FreeCSPInfo(pCspInfo);
if (SUCCEEDED(hr))
{
ULONG ulAuthPackage;
hr = RetrieveNegotiateAuthPackage(&ulAuthPackage);
if (SUCCEEDED(hr))
{
pcpcs->ulAuthenticationPackage = ulAuthPackage;
pcpcs->clsidCredentialProvider = CLSID_CProvider;
// At this point the credential has created the serialized credential used for logon
// By setting this to CPGSR_RETURN_CREDENTIAL_FINISHED we are letting logonUI know
// that we have all the information we need and it should attempt to submit the
// serialized credential.
*pcpgsr = CPGSR_RETURN_CREDENTIAL_FINISHED;
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"RetrieveNegotiateAuthPackage not SUCCEEDED hr=0x%08x", hr);
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"UnlockLogonPack not SUCCEEDED hr=0x%08x", hr);
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"pCspInfo NULL");
}
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"UnlockLogonInit not SUCCEEDED hr=0x%08x", hr);
}
CoTaskMemFree(pwzProtectedPin);
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"ProtectIfNecessaryAndCopyPassword not SUCCEEDED hr=0x%08x", hr);
}
if (!SUCCEEDED(hr))
{
PrintLn(WINEVENT_LEVEL_WARNING, L"not SUCCEEDED hr=0x%08x", hr);
}
else
{
PrintLn(WINEVENT_LEVEL_WARNING, L"OK");
}
return hr;
}
UnlockLogonInit
HRESULT UnlockLogonInit(
PWSTR pwzDomain,
PWSTR pwzUsername,
PWSTR pwzPin,
CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus,
KERB_CERTIFICATE_UNLOCK_LOGON* pkiul
)
{
UNREFERENCED_PARAMETER(cpus);
KERB_CERTIFICATE_UNLOCK_LOGON kiul;
ZeroMemory(&kiul, sizeof(kiul));
KERB_CERTIFICATE_LOGON* pkil = &kiul.Logon;
HRESULT hr = UnicodeStringInitWithString(pwzDomain, &pkil->LogonDomainName);
if (SUCCEEDED(hr))
{
hr = UnicodeStringInitWithString(pwzUsername, &pkil->UserName);
if (SUCCEEDED(hr))
{
hr = UnicodeStringInitWithString(pwzPin, &pkil->Pin);
if (SUCCEEDED(hr))
{
// Set a MessageType based on the usage scenario.
pkil->MessageType = KerbCertificateLogon; //13
pkil->CspDataLength = 0;
pkil->CspData = NULL;
pkil->Flags = 0;
if (SUCCEEDED(hr))
{
// KERB_INTERACTIVE_UNLOCK_LOGON is just a series of structures. A
// flat copy will properly initialize the output parameter.
CopyMemory(pkiul, &kiul, sizeof(*pkiul));
}
}
}
}
return hr;
}
UnlockLogonPack
HRESULT UnlockLogonPack(
const KERB_CERTIFICATE_UNLOCK_LOGON& rkiulIn,
const PBASE_SMARTCARD_CSP_INFO pCspInfo,
BYTE** prgb,
DWORD* pcb
)
{
HRESULT hr;
const KERB_CERTIFICATE_LOGON* pkilIn = &rkiulIn.Logon;
// alloc space for struct plus extra for the three strings
DWORD cb = sizeof(rkiulIn) +
pkilIn->LogonDomainName.Length +
pkilIn->UserName.Length +
pkilIn->Pin.Length +
pCspInfo->dwCspInfoLen;
KERB_CERTIFICATE_UNLOCK_LOGON* pkiulOut = (KERB_CERTIFICATE_UNLOCK_LOGON*)CoTaskMemAlloc(cb);
if (pkiulOut)
{
ZeroMemory(&pkiulOut->LogonId, sizeof(LUID));
//
// point pbBuffer at the beginning of the extra space
//
BYTE* pbBuffer = (BYTE*)pkiulOut + sizeof(*pkiulOut);
KERB_CERTIFICATE_LOGON* pkilOut = &pkiulOut->Logon;
pkilOut->MessageType = pkilIn->MessageType;
pkilOut->Flags = pkilIn->Flags;
//
// copy each string,
// fix up appropriate buffer pointer to be offset,
// advance buffer pointer over copied characters in extra space
//
_UnicodeStringPackedUnicodeStringCopy(pkilIn->LogonDomainName, (PWSTR)pbBuffer, &pkilOut->LogonDomainName);
pkilOut->LogonDomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->LogonDomainName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->UserName, (PWSTR)pbBuffer, &pkilOut->UserName);
pkilOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->UserName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->Pin, (PWSTR)pbBuffer, &pkilOut->Pin);
pkilOut->Pin.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->Pin.Length;
pkilOut->CspData = (PUCHAR) (pbBuffer - (BYTE*)pkiulOut);
pkilOut->CspDataLength = pCspInfo->dwCspInfoLen;
memcpy(pbBuffer,pCspInfo,pCspInfo->dwCspInfoLen);
*prgb = (BYTE*)pkiulOut;
*pcb = cb;
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
_KERB_SMARTCARD_CSP_INFO Structure and GetCSPInfo
// based on _KERB_SMARTCARD_CSP_INFO
typedef struct _BASE_SMARTCARD_CSP_INFO
{
DWORD dwCspInfoLen;
DWORD MessageType;
union {
PVOID ContextInformation;
ULONG64 SpaceHolderForWow64;
} ;
DWORD flags;
DWORD KeySpec;
ULONG nCardNameOffset;
ULONG nReaderNameOffset;
ULONG nContainerNameOffset;
ULONG nCSPNameOffset;
TCHAR bBuffer[sizeof(DWORD)];
} BASE_SMARTCARD_CSP_INFO,
*PBASE_SMARTCARD_CSP_INFO;
PBASE_SMARTCARD_CSP_INFO CContainer::GetCSPInfo()
{
//szreaderName, szCardname, szproviderName, szContainerName are initialized with respective values in constructor
_ASSERTE( _CrtCheckMemory( ) );
DWORD dwReaderLen = (DWORD) _tcslen(_szReaderName)+1;
DWORD dwCardLen = (DWORD) _tcslen(_szCardName)+1;
DWORD dwProviderLen = (DWORD) _tcslen(_szProviderName)+1;
DWORD dwContainerLen = (DWORD) _tcslen(_szContainerName)+1;
DWORD dwBufferSize = dwReaderLen + dwCardLen + dwProviderLen + dwContainerLen;
PBASE_SMARTCARD_CSP_INFO pCspInfo = (PBASE_SMARTCARD_CSP_INFO) BASEAlloc(sizeof(BASE_SMARTCARD_CSP_INFO)+dwBufferSize*sizeof(TCHAR));
if (!pCspInfo) return NULL;
//ZeroMemory(pCspInfo);
memset(pCspInfo,0,sizeof(BASE_SMARTCARD_CSP_INFO));
pCspInfo->dwCspInfoLen = sizeof(BASE_SMARTCARD_CSP_INFO)+dwBufferSize*sizeof(TCHAR);
pCspInfo->MessageType = 1;
pCspInfo->KeySpec = _KeySpec;
pCspInfo->nCardNameOffset = ARRAYSIZE(pCspInfo->bBuffer);
pCspInfo->nReaderNameOffset = pCspInfo->nCardNameOffset + dwCardLen;
pCspInfo->nContainerNameOffset = pCspInfo->nReaderNameOffset + dwReaderLen;
pCspInfo->nCSPNameOffset = pCspInfo->nContainerNameOffset + dwContainerLen;
memset(pCspInfo->bBuffer,0,sizeof(pCspInfo->bBuffer));
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nCardNameOffset] ,dwBufferSize + 4 - pCspInfo->nCardNameOffset, _szCardName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nReaderNameOffset] ,dwBufferSize + 4 - pCspInfo->nReaderNameOffset, _szReaderName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nContainerNameOffset] ,dwBufferSize + 4 - pCspInfo->nContainerNameOffset, _szContainerName);
_tcscpy_s(&pCspInfo->bBuffer[pCspInfo->nCSPNameOffset] ,dwBufferSize + 4 - pCspInfo->nCSPNameOffset, _szProviderName);
_ASSERTE( _CrtCheckMemory( ) );
return pCspInfo;
}
I don't understand where I am doing wrong, been stuck here for a while now. Any help would be appreciated.
my goal:
I`m writing an application which writes a file to the serial port 128 bytes at a time (137 total, with ModBUS header and CRC) and waits for the reply. The writing I have managed to implement successfully. After sending a 137 byte packet I would like to wait on the serial com for a reply and process it, in case that modbus exception is thrown.
my problem:
The ReadFile function returns 170 which, from windows documentation, is 170 (0xAA) - The requested resource is in use. The only resource I am actually using is the serial port handle, which I doubt that it is this, the error is referring to.
Note -
- not using available ModBUS libraries because I use the address registers in a specific way, needing full control
- I am using overlapped I/O only because (according to WinApi doc) ReadFile never returns if no bytes come at the serial port; If timeouts are require overlapped access is a must (correct me if I`m wrong).
- I have a 2 sec max timeout (timeout for actually waiting for the reply) and 20 ms between bytes; if more than 20 ms between bytes pass I assume that no more bytes are coming;
Has anyone had any previous experience working with ReadFile and possibly Erro 170? Appreciate all the help I can get.
part of my code:
u8 WaitModBusReply(void)
{
u8 i = 0;
u8 ReplyStatus = 0xAA;
u8 ReplyBuff[ReplyBuffSize];
u8 * ptr = &ReplyBuff[0];
static u16 TotalRX_Bytes;
DWORD dwCommEvent;
DWORD dwBytesRead;
COMSTAT ComStatus;
DWORD comErrors = 0;
OVERLAPPED read_s = {0};
read_s.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
for (int z=0; z< ReplyBuffSize; z++)
ReplyBuff[z] = 0;
ClearCommError(ModBUS_Port, &comErrors, &ComStatus);
ResetEvent(read_s.hEvent);
if ( !WaitCommEvent(ModBUS_Port, &dwCommEvent, &read_s) )
{
//byte_timeout += MCU_Getms_TimeConsumption();
if ( (ReadFile(ModBUS_Port, ptr+TotalRX_Bytes, ReplyBuffSize-
TotalRX_Bytes, &dwBytesRead, NULL) )) //&dwBytesRead &modbus_reply
{
fprintf(stderr, "\n EXEC 3");
// ReadFile(PC_TestCenterPort, pBufPtr+TotalRX_Bytes, BufSize-
TotalRX_Bytes, &BytesRead, NULL);
TotalRX_Bytes += dwBytesRead;
i++;
ReplyStatus = Reply_Received;
}
}
else
printf("Error setting Com event mask:%d ", GetLastError());
if ( ReplyStatus == Reply_Received)
{
fprintf(stderr, "\nExit error3: %d\n", GetLastError() );
if ( (i == 4) ) // Exception returned. Parse it
{
if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
ReplyStatus = Reply_CRCError;
else
ReplyStatus = ReplyBuff[i-2];
}
else if ( (i == 7) ) // Reply returned
{
if ( !ModBus_CRC16 (&ReplyBuff[0], i, READ) )
ReplyStatus = Reply_CRCError;
else
ReplyStatus = Reply_OK;
}
}
/*
for ( int j=0; j<= 256; j++)
printf("\nReplyBuff[%d]: %X", j, ReplyBuff[j]); */
return ReplyStatus;
}
The logic for checking the reply array is not implemented so ignore that part.
This function is called by:
u8 SerialDataSend(void)
{
u8 t_status = BufferSent;
int write_status = -1;
int read_status = -1;
DWORD bytes_written = 0;
OVERLAPPED write_s;
memset(&write_s, 0, sizeof(write_s));
write_s.Internal = 0;
write_s.InternalHigh = 0;
write_s.Offset = 0;
write_s.OffsetHigh = 0;
write_s.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if ( !SerialInit() )
{
while (!t_status)
{
fprintf(stderr, "Starting transmission -\n");
while(packages_left > 0 && !t_status)
{
write_status = WriteFile(ModBUS_Port, ModBUS_Buffer(), 137,
&bytes_written, &write_s); //&write_s
fprintf(stderr,"\r ModBUS transaction - Packages left:%4d",
packages_left);
if( write_status ) // Return values for success and
overlapped access ongoing
{
fprintf(stderr, "Error :%d.\n", GetLastError());
t_status = BufferFailed;
CloseHandle(ModBUS_Port);
break;
}
//FlushFileBuffers(ModBUS_Port);
read_status = WaitModBusReply();
printf("READ STATUS: %d\n", read_status);
if ( !read_status && !write_status )
{
fprintf(stderr, "\n------------------------------------------------------------");
fprintf(stderr, "\n Exception occurred: %X\n",
read_status);
t_status = BufferFailed;
Sleep(1);
break;
}
packages_left--;
Sleep(200);
}
//printf("EXEC 1\n");
if (!t_status)
{
fprintf(stderr, "\n\nTransaction Complete. Bytes written :
%d\n", FileSize);
packages_left = 10;
}
break;
}
fclose(HMI_Program);
if ( t_status != BufferFailed )
{
fprintf(stderr, "Closing serial port - ");
if ( !CloseHandle(ModBUS_Port) )
fprintf(stderr, "Error :%d.\n", GetLastError());
else
fprintf(stderr, "OK.\n");
}
}
fflush(stdout);
fflush(stderr);
return t_status;
}
and the function which initializes the Serial port:
u8 SerialInit(void)
{
memset(&SerialSettings,0,sizeof(SerialSettings));
SerialSettings.DCBlength = sizeof(SerialSettings);
SerialSettings.BaudRate = CBR_115200;
SerialSettings.ByteSize = 8;
SerialSettings.StopBits = TWOSTOPBITS;
SerialSettings.Parity = NOPARITY;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.ReadIntervalTimeout = 20;
timeouts.ReadTotalTimeoutConstant = 2000;
timeouts.ReadTotalTimeoutMultiplier = 1 ;
memset(&timeouts,0,sizeof(timeouts));
fprintf(stderr, "Opening serial port - ");
sprintf(COM_Port, "\\\\.\\COM%d", port_no);
ModBUS_Port = CreateFile(COM_Port, GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
if (ModBUS_Port == INVALID_HANDLE_VALUE)
fprintf(stderr, "Error\n\n");
else
fprintf(stderr, "OK\n");
if ( !GetCommState(ModBUS_Port, &SerialSettings) )
{
fprintf(stderr, "Error getting device state.");
CloseHandle(ModBUS_Port);
}
else if( !SetCommState(ModBUS_Port, &SerialSettings) )
{
fprintf(stderr, "Error setting device parameters.");
CloseHandle(ModBUS_Port);
}
else if ( !SetCommTimeouts(ModBUS_Port, &timeouts) )
{
fprintf(stderr, "Error setting timeouts.");
CloseHandle(ModBUS_Port);
}
else if ( !SetCommMask(ModBUS_Port, EV_RXCHAR | EV_ERR ) )
{
fprintf(stderr, "\nError setting com mask.");
CloseHandle(ModBUS_Port);
}
return GetLastError();
}
Thanks.
This is continuation to my previous question - phase 2 so to say.
First question was here: Fast capture stack trace on windows / 64-bit / mixed mode
Now I have resolved a huge amount of stack traces and now wondering how to resolve symbol information of managed stack frames.
For native C++ side it's relatively simple -
First you specify which process from where to take symbols:
HANDLE g_hProcess = GetCurrentProcess();
Where you can replace process in run-time using code snipet like this:
g_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, g_processId);
b = (g_hProcess != NULL );
if( !b )
errInfo.AppendFormat(_T("Process id '%08X' is not running anymore."), g_processId );
else
InitSymbolLoad();
And initialize symbol loading:
void InitSymbolLoad()
{
SymInitialize(g_hProcess, NULL, TRUE);
DWORD dwFlags = SymGetOptions();
SymSetOptions(SymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_NO_IMAGE_SEARCH);
}
And after that resolve native symbol , somehow like this:
extern HANDLE g_hProcess;
void StackFrame::Resolve()
{
struct {
union
{
SYMBOL_INFO symbol;
char buf[sizeof(SYMBOL_INFO) + 1024];
}u;
}ImageSymbol = { 0 };
HANDLE hProcess = g_hProcess;
DWORD64 offsetFromSymbol = 0;
ImageSymbol.u.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
ImageSymbol.u.symbol.Name[0] = 0;
ImageSymbol.u.symbol.MaxNameLen = sizeof(ImageSymbol) - sizeof(SYMBOL_INFO);
SYMBOL_INFO* pSymInfo = &ImageSymbol.u.symbol;
// Get file / line of source code.
IMAGEHLP_LINE64 lineStr = { 0 };
lineStr.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
function.clear();
if( SymGetLineFromAddr64(hProcess, (DWORD64)ip, (DWORD*)&offsetFromSymbol, &lineStr) )
{
function = lineStr.FileName;
function += "(";
function += std::to_string((_ULonglong) lineStr.LineNumber).c_str();
function += "): ";
}
// Successor of SymGetSymFromAddr64.
if( SymFromAddr(hProcess, (DWORD64)ip, &offsetFromSymbol, pSymInfo) )
function += ImageSymbol.u.symbol.Name;
}
This looks like working.
But now also managed stack frames.
There are two interfaces which I've located:
IDebugClient / GetNameByOffset
Mentioned in:
http://www.codeproject.com/Articles/371137/A-Mixed-Mode-Stackwalk-with-the-IDebugClient-Inter
(*) (Includes sample code)
http://blog.steveniemitz.com/building-a-mixed-mode-stack-walker-part-1/
Used by:
https://github.com/okigan/CrashInsight (Code not touched for 4 years)
Mixed mode stackwalk article provides good example.
IXCLRDATAProcess / GetRuntimeNameByAddress
Mentioned also in two links above.
Used by process hacker (GPL license, C style)
Implementation seems to reside in here:
https://github.com/dotnet/coreclr/blob/master/src/debug/daccess/daccess.cpp
(Based on commits this code is quite alive)
ICorProfiler / ???
Mentioned at the end of (*) article.
Approach 1 seems to be quite old fashioned, also article (*) mentions some problems around it.
Approach 3 will probably require in-depth analysis of profiling API's.
There is also one mention I have found about these API's - in here:
https://naughter.wordpress.com/2015/05/24/changes-in-the-windows-10-sdk-compared-to-windows-8-1-part-two/
· cor.h, cordebug.h/idl, CorError.h, CorHdr.h, corhlpr.h,
corprof.h/idl, corpub.h/idl & corsym.h/idl: All of these header files
have been removed. They are all the native mode COM interface to .NET.
This sentence I don't fully understand. Are those interfaces dead or replaced or what happened to them ?
So I guess based on my brief analysis approach 2 is only good / alive API interface which is worth of using ? Have you came across any problems related to those api's.
After walking through huge amount of code samples and interfaces, I've understood that there aren't any simple to use API interface. Code and API's developed for native C++ works only with native C++, and code and API's developed for managed code works only with managed code.
There is additionally problem of resolving stack trace afterwards might not work. You see - developer can generate code dynamically on fly using Jit engine / IL Generator, and dispose it as well - so after you have "void*" / instruction address - you should resolve symbolic information right away, not afterwards. But I'll leave this for time being, will assume that developer is not too fancy coder and not generating and disposing new code all the times, and FreeLibrary will not be called without need. (May be I can address this later on if I'll hook FreeLibrary / Jit components.)
Resolving function name was quite trivial, through IXCLRDataProcess with little bit of magic and luck - I was able to get function names, however - I want to expand it deeper - into exact source code path and source code line where code were executing, and this turned to be quite complex functionality to reach.
Finally I've hit upon source code where such thing were performed - and it was done here:
https://github.com/dotnet/coreclr/blob/master/src/ToolBox/SOS/Strike/util.cpp
GetLineByOffset is function name in that file.
I've analyzed, retuned and made my own solution from that source code, which I'm now attaching here now:
Updated code can be found from here:
https://sourceforge.net/projects/diagnostic/
But here is just a snapshot of same code taken at some point of time:
ResolveStackM.h:
#pragma once
#include <afx.h>
#pragma warning (disable: 4091) //dbghelp.h(1544): warning C4091: 'typedef ': ignored on left of '' when no variable is declared
#include <cor.h> //xclrdata.h requires this
#include "xclrdata.h" //IXCLRDataProcess
#include <atlbase.h> //CComPtr
#include <afxstr.h> //CString
#include <crosscomp.h> //TCONTEXT
#include <Dbgeng.h> //IDebugClient
#pragma warning (default: 4091)
class ResoveStackM
{
public:
ResoveStackM();
~ResoveStackM();
void Close(void);
bool InitSymbolResolver(HANDLE hProcess, CString& lastError);
bool GetMethodName(void* ip, CStringA& methodName);
bool GetManagedFileLineInfo(void* ip, CStringA& lineInfo);
HMODULE mscordacwks_dll;
CComPtr<IXCLRDataProcess> clrDataProcess;
CComPtr<ICLRDataTarget> target;
CComPtr<IDebugClient> debugClient;
CComQIPtr<IDebugControl> debugControl;
CComQIPtr<IDebugSymbols> debugSymbols;
CComQIPtr<IDebugSymbols3> debugSymbols3;
};
//
// Typically applications don't need more than one instance of this. If you do, use your own copies.
//
extern ResoveStackM g_managedStackResolver;
ResolveStackM.cpp:
#include "ResolveStackM.h"
#include <Psapi.h> //EnumProcessModules
#include <string> //to_string
#pragma comment( lib, "dbgeng.lib" )
class CLRDataTarget : public ICLRDataTarget
{
public:
ULONG refCount;
bool bIsWow64;
HANDLE hProcess;
CLRDataTarget( HANDLE _hProcess, bool _bIsWow64 ) :
refCount(1),
bIsWow64(_bIsWow64),
hProcess(_hProcess)
{
}
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, PVOID* ppvObject)
{
if ( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, __uuidof(ICLRDataTarget)) )
{
AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef( void)
{
return ++refCount;
}
ULONG STDMETHODCALLTYPE Release( void)
{
refCount--;
if( refCount == 0 )
delete this;
return refCount;
}
virtual HRESULT STDMETHODCALLTYPE GetMachineType( ULONG32 *machineType )
{
#ifdef _WIN64
if (!bIsWow64)
*machineType = IMAGE_FILE_MACHINE_AMD64;
else
*machineType = IMAGE_FILE_MACHINE_I386;
#else
*machineType = IMAGE_FILE_MACHINE_I386;
#endif
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetPointerSize( ULONG32* pointerSize )
{
#ifdef _WIN64
if (!bIsWow64)
#endif
*pointerSize = sizeof(PVOID);
#ifdef _WIN64
else
*pointerSize = sizeof(ULONG);
#endif
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetImageBase( LPCWSTR imagePath, CLRDATA_ADDRESS *baseAddress )
{
HMODULE dlls[1024] = { 0 };
DWORD nItems = 0;
wchar_t path[ MAX_PATH ];
DWORD whatToList = LIST_MODULES_ALL;
if( bIsWow64 )
whatToList = LIST_MODULES_32BIT;
if( !EnumProcessModulesEx( hProcess, dlls, sizeof(dlls), &nItems, whatToList ) )
{
DWORD err = GetLastError();
return HRESULT_FROM_WIN32(err);
}
nItems /= sizeof(HMODULE);
for( unsigned int i = 0; i < nItems; i++ )
{
path[0] = 0;
if( GetModuleFileNameEx(hProcess, dlls[i], path, sizeof(path) / sizeof(path[0])) )
{
wchar_t* pDll = wcsrchr( path, L'\\');
if (pDll) pDll++;
if (_wcsicmp(imagePath, path) == 0 || _wcsicmp(imagePath, pDll) == 0)
{
*baseAddress = (CLRDATA_ADDRESS) dlls[i];
return S_OK;
}
}
}
return E_FAIL;
}
virtual HRESULT STDMETHODCALLTYPE ReadVirtual( CLRDATA_ADDRESS address, BYTE *buffer, ULONG32 bytesRequested, ULONG32 *bytesRead )
{
SIZE_T readed;
if( !ReadProcessMemory(hProcess, (void*)address, buffer, bytesRequested, &readed) )
return HRESULT_FROM_WIN32( GetLastError() );
*bytesRead = (ULONG32) readed;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE WriteVirtual( CLRDATA_ADDRESS address, BYTE *buffer, ULONG32 bytesRequested, ULONG32 *bytesWritten )
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetTLSValue( ULONG32 threadID, ULONG32 index, CLRDATA_ADDRESS *value )
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE SetTLSValue( ULONG32 threadID, ULONG32 index, CLRDATA_ADDRESS value )
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadID( ULONG32 *threadID )
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE GetThreadContext( ULONG32 threadID, ULONG32 contextFlags, ULONG32 contextSize, BYTE *context )
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE SetThreadContext( ULONG32 threadID, ULONG32 contextSize, BYTE *context)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE Request( ULONG32 reqCode, ULONG32 inBufferSize, BYTE *inBuffer, ULONG32 outBufferSize, BYTE *outBuffer)
{
return E_NOTIMPL;
}
}; //CLRDataTarget
ResoveStackM::ResoveStackM() :
mscordacwks_dll(0)
{
}
ResoveStackM::~ResoveStackM()
{
Close();
}
void ResoveStackM::Close( void )
{
clrDataProcess.Release();
target.Release();
debugClient.Release();
if( mscordacwks_dll != 0 )
{
FreeLibrary(mscordacwks_dll);
mscordacwks_dll = 0;
}
}
bool ResoveStackM::InitSymbolResolver(HANDLE hProcess, CString& lastError)
{
wchar_t path[ MAX_PATH ] = { 0 };
// According to process hacker - mscoree.dll must be loaded before loading mscordacwks.dll.
// It's enough if base application is managed.
if( GetWindowsDirectoryW(path, sizeof(path)/sizeof(wchar_t) ) == 0 )
return false; //Unlikely to fail.
#ifdef _WIN64
wcscat(path, L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll");
#else
wcscat(path, L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll");
#endif
mscordacwks_dll = LoadLibraryW(path);
PFN_CLRDataCreateInstance pCLRCreateInstance = 0;
if( mscordacwks_dll != 0 )
pCLRCreateInstance = (PFN_CLRDataCreateInstance) GetProcAddress(mscordacwks_dll, "CLRDataCreateInstance");
if( mscordacwks_dll == 0 || pCLRCreateInstance == 0)
{
lastError.Format(L"Required dll mscordacwks.dll from .NET4 installation was not found (%s)", path);
Close();
return false;
}
BOOL isWow64 = FALSE;
IsWow64Process(hProcess, &isWow64);
target.Attach( new CLRDataTarget(hProcess, isWow64 != FALSE) );
HRESULT hr = pCLRCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&clrDataProcess );
if( FAILED(hr) )
{
lastError.Format(L"Failed to initialize mscordacwks.dll for symbol resolving (%08X)", hr);
Close();
return false;
}
hr = DebugCreate(__uuidof(IDebugClient), (void**)&debugClient);
if (FAILED(hr))
{
lastError.Format(_T("Could retrieve symbolic debug information using dbgeng.dll (Error code: 0x%08X)"), hr);
return false;
}
DWORD processId = GetProcessId(hProcess);
const ULONG64 LOCAL_SERVER = 0;
int flags = DEBUG_ATTACH_NONINVASIVE | DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND;
hr = debugClient->AttachProcess(LOCAL_SERVER, processId, flags);
if (hr != S_OK)
{
lastError.Format(_T("Could attach to process 0x%X (Error code: 0x%08X)"), processId, hr);
Close();
return false;
}
debugControl = debugClient;
hr = debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
if ((hr = debugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, INFINITE)) != S_OK)
{
return false;
}
debugSymbols3 = debugClient;
debugSymbols = debugClient;
// if debugSymbols3 == NULL - GetManagedFileLineInfo will not work
return true;
} //Init
struct ImageInfo
{
ULONG64 modBase;
};
// Based on a native offset, passed in the first argument this function
// identifies the corresponding source file name and line number.
bool ResoveStackM::GetManagedFileLineInfo( void* ip, CStringA& lineInfo )
{
ULONG lineN = 0;
char path[MAX_PATH];
ULONG64 dispacement = 0;
CComPtr<IXCLRDataMethodInstance> method;
if (!debugSymbols || !debugSymbols3)
return false;
// Get managed method by address
CLRDATA_ENUM methEnum;
HRESULT hr = clrDataProcess->StartEnumMethodInstancesByAddress((ULONG64)ip, NULL, &methEnum);
if( hr == S_OK )
{
hr = clrDataProcess->EnumMethodInstanceByAddress(&methEnum, &method);
clrDataProcess->EndEnumMethodInstancesByAddress(methEnum);
}
if (!method)
goto lDefaultFallback;
ULONG32 ilOffsets = 0;
hr = method->GetILOffsetsByAddress((CLRDATA_ADDRESS)ip, 1, NULL, &ilOffsets);
switch( (long)ilOffsets )
{
case CLRDATA_IL_OFFSET_NO_MAPPING:
goto lDefaultFallback;
case CLRDATA_IL_OFFSET_PROLOG:
// Treat all of the prologue as part of the first source line.
ilOffsets = 0;
break;
case CLRDATA_IL_OFFSET_EPILOG:
{
// Back up until we find the last real IL offset.
CLRDATA_IL_ADDRESS_MAP mapLocal[16];
CLRDATA_IL_ADDRESS_MAP* map = mapLocal;
ULONG32 count = _countof(mapLocal);
ULONG32 needed = 0;
for( ; ; )
{
hr = method->GetILAddressMap(count, &needed, map);
if ( needed <= count || map != mapLocal)
break;
map = new CLRDATA_IL_ADDRESS_MAP[ needed ];
}
ULONG32 highestOffset = 0;
for (unsigned i = 0; i < needed; i++)
{
long l = (long) map[i].ilOffset;
if (l == CLRDATA_IL_OFFSET_NO_MAPPING || l == CLRDATA_IL_OFFSET_PROLOG || l == CLRDATA_IL_OFFSET_EPILOG )
continue;
if (map[i].ilOffset > highestOffset )
highestOffset = map[i].ilOffset;
} //for
if( map != mapLocal )
delete[] map;
ilOffsets = highestOffset;
}
break;
} //switch
mdMethodDef methodToken;
void* moduleBase = 0;
{
CComPtr<IXCLRDataModule> module;
hr = method->GetTokenAndScope(&methodToken, &module);
if( !module )
goto lDefaultFallback;
//
// Retrieve ImageInfo associated with the IXCLRDataModule instance passed in. First look for NGENed module, second for IL modules.
//
for (int extentType = CLRDATA_MODULE_PREJIT_FILE; extentType >= CLRDATA_MODULE_PE_FILE; extentType--)
{
CLRDATA_ENUM enumExtents;
if (module->StartEnumExtents(&enumExtents) != S_OK )
continue;
CLRDATA_MODULE_EXTENT extent;
while (module->EnumExtent(&enumExtents, &extent) == S_OK)
{
if (extentType != extent.type )
continue;
ULONG startIndex = 0;
ULONG64 modBase = 0;
hr = debugSymbols->GetModuleByOffset((ULONG64) extent.base, 0, &startIndex, &modBase);
if( FAILED(hr) )
continue;
moduleBase = (void*)modBase;
if (moduleBase )
break;
}
module->EndEnumExtents(enumExtents);
if( moduleBase != 0 )
break;
} //for
} //module scope
DEBUG_MODULE_AND_ID id;
DEBUG_SYMBOL_ENTRY symInfo;
hr = debugSymbols3->GetSymbolEntryByToken((ULONG64)moduleBase, methodToken, &id);
if( FAILED(hr) )
goto lDefaultFallback;
hr = debugSymbols3->GetSymbolEntryInformation(&id, &symInfo);
if (FAILED(hr))
goto lDefaultFallback;
char* IlOffset = (char*)symInfo.Offset + ilOffsets;
//
// Source maps for managed code can end up with special 0xFEEFEE markers that
// indicate don't-stop points. Try and filter those out.
//
for (ULONG SkipCount = 64; SkipCount > 0; SkipCount--)
{
hr = debugSymbols3->GetLineByOffset((ULONG64)IlOffset, &lineN, path, sizeof(path), NULL, &dispacement );
if( FAILED( hr ) )
break;
if (lineN == 0xfeefee)
IlOffset++;
else
goto lCollectInfoAndReturn;
}
if( !FAILED(hr) )
// Fall into the regular translation as a last-ditch effort.
ip = IlOffset;
lDefaultFallback:
hr = debugSymbols3->GetLineByOffset((ULONG64) ip, &lineN, path, sizeof(path), NULL, &dispacement);
if( FAILED(hr) )
return false;
lCollectInfoAndReturn:
lineInfo += path;
lineInfo += "(";
lineInfo += std::to_string((_ULonglong) lineN).c_str();
lineInfo += "): ";
return true;
}
bool ResoveStackM::GetMethodName(void* ip, CStringA& symbol)
{
symbol.Empty();
GetManagedFileLineInfo(ip, symbol);
USES_CONVERSION;
CLRDATA_ADDRESS displacement = 0;
ULONG32 len = 0;
wchar_t name[1024];
if (!clrDataProcess )
return false;
HRESULT hr = clrDataProcess->GetRuntimeNameByAddress( (CLRDATA_ADDRESS)ip, 0, sizeof(name) / sizeof(name[0]), &len, name, &displacement );
if( FAILED( hr ) )
return false;
name[ len ] = 0;
symbol += W2A(name);
return true;
} //GetMethodName
ResoveStackM g_managedStackResolver;
So far tested only with some smaller piece of code, only 64-bit (doubt that 32-bit works at all - I don't have call stack determination yet for it).
It's possible that this code contains bugs, but I'll try to haunt them down and fix them.
I harvested so much code that please mark this answer as useful. :-)
Here is an answer from Jan Kotas on this:
From: Jan Kotas <jkotas#microsoft.com>
To: Tarmo Pikaro <tapika#yahoo.com>
Sent: Tuesday, January 12, 2016 5:09 AM
Subject: RE: Fast capture stack trace on windows 64 bit / mixed mode...
Your solution based on IXCLRDATAProcess sounds good to me.
PerfView (https://www.microsoft.com/en-us/download/details.aspx?id=28567) –
that does what you are trying to build as well as a lot of other stuff – is
using IXCLRDATA* as well. You may be interested in
https://github.com/Microsoft/clrmd . It is set of managed wrappers for
IXCLRDATA* that are easier to use than the COM interfaces.
What I have briefly tried out - this requires Visual Studio 2015 / C# 6.0.
Also this technique is unusable. Like .net StackTrace / StackFrame are resolving call stack and symbol information right away - and I need to resolve symbol information afterwards (after stack trace capturing).
Alternative 1 / IDebugClient / GetNameByOffset is not usable for managed stack trace, it can be used for native code only - as for native call stack I have demo code snipet above already. Not sure whether IDebugClient provides something more than SymGetLineFromAddr64 / SymFromAddr does not provide - not sure.
This is from a 2009 Microsoft project, and I'm not sure why I'm getting an error specifically in Windows-8. Here is the link: MSDN MFCopy
This happens when using the '-v' option 'Set Video Format', I get this error:
"Failed to negotiate a format between the source reader and sink writer".
Keep in mind, I am processing the same video files in Win-7 and 8.
Edit: Is this a WinAPI issue? Is there some differences in the calls that need to be made? if so, can that be repaired in the source...
Example Usage is:
MfCopy.exe -t -xa -v WVC1 -r 270 "g:\pd1.mov" "g:\pd3.wmv"
'-t' = Trim Black frames
'-xa' = Video only
'-r' (270) = Rotate 270 degrees
'-v' (WVC1) = (Video options, H264, WMV2, WMV3, WVC1... none work in Win-8)
I also have the sourcecode, and I can debug. Again it runs fine in Win-7. But in Win-8, I get an error specifically at this line:
hr = m_pSinkWriter->SetInputMediaType( streamInfo.dwOutputStreamIndex,
pFullMediaType,
NULL );
The error is: 'The data specified for the media type is invalid, inconsistent, or not supported by this object'.
That is in this code block:
/////////////////////////////////////////////////////////////////
HRESULT CMFCopy::_NegotiateStreamFormat(
__in DWORD dwStreamIndex,
__in REFGUID guidMajorType,
__in DWORD cFormats,
__in_ecount( cFormats ) const GUID **paFormats )
{
HRESULT hr = S_OK;
const StreamInfo& streamInfo = m_paStreamInfo[dwStreamIndex];
IMFMediaType *pPartialMediaType = NULL;
IMFMediaType *pFullMediaType = NULL;
BOOL fConfigured = FALSE;
CHECK_HR( hr = MFCreateMediaType( &pPartialMediaType ) );
CHECK_HR( hr = pPartialMediaType->SetGUID( MF_MT_MAJOR_TYPE, guidMajorType ) );
for( DWORD ii = 0; ii < cFormats; ii++ )
{
SAFE_RELEASE( pFullMediaType );
CHECK_HR( hr = pPartialMediaType->SetGUID( MF_MT_SUBTYPE, *paFormats[ii] ) );
// try to set the partial media type on the source reader
hr = m_pSourceReader->SetCurrentMediaType( dwStreamIndex,
NULL,
pPartialMediaType );
if( S_OK != hr )
{
// format is not supported by the source reader, try the next on the list
hr = S_OK;
continue;
}
// get the full media type from the source reader
CHECK_HR( hr = m_pSourceReader->GetCurrentMediaType( dwStreamIndex,
&pFullMediaType ) );
if (MFMediaType_Video == guidMajorType)
{
_UpdateInputVideoStreamOverscanLineCount(pFullMediaType);
if (RotateNone != m_Options.eRotation)
{
CHECK_HR( hr = GetDefaultStride(pFullMediaType, &m_srcDefaultStride)); // get the default stride for the source
CComPtr<IMFMediaType> spRotatedMediaType;
CHECK_HR(hr = hr = CreateRotatedMediaType(pFullMediaType, spRotatedMediaType, _simpleOverScanLines));
pFullMediaType->Release();
pFullMediaType = spRotatedMediaType.Detach(); // transfer ownership
}
}
// try to set the input media type on the sink writer
hr = m_pSinkWriter->SetInputMediaType( streamInfo.dwOutputStreamIndex,
pFullMediaType,
NULL );
if( S_OK != hr )
{
// format is not supported by the sink writer, try the next on the list
hr = S_OK;
continue;
}
if (MFMediaType_Video == guidMajorType)
{
CHECK_HR( hr = _UpdateRotationInfo(pFullMediaType)); // may need to update info about rotated image
}
fConfigured = TRUE;
break;
}
if( !fConfigured )
{
hr = MF_E_INVALIDMEDIATYPE;
_SetErrorDetails( hr, L"Failed to negotiate a format between the source reader and sink writer" );
goto done;
}
done:
SAFE_RELEASE( pPartialMediaType );
SAFE_RELEASE( pFullMediaType );
return( hr );
}