I am new to the concept of MSMQ(Microsoft Message Queues). I had a glimpse of the sample code from Microsoft's link and am trying to create a simple MSMQ queue. Here is my full code (mostly from Microsoft's link).
#include "stdafx.h"
#include "windows.h"
#include "mq.h"
#pragma comment (lib, "Mqrt.lib")
#include "tchar.h"
#include <stdio.h>
#define BUFLEN = 256;
#include <iostream>
HRESULT CreateMSMQQueue(
LPWSTR wszPathName,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
LPWSTR wszOutFormatName,
DWORD *pdwOutFormatNameLength
)
{
// Define the maximum number of queue properties.
const int NUMBEROFPROPERTIES = 2;
// Define a queue property structure and the structures needed to initialize it.
MQQUEUEPROPS QueueProps;
MQPROPVARIANT aQueuePropVar[NUMBEROFPROPERTIES];
QUEUEPROPID aQueuePropId[NUMBEROFPROPERTIES];
HRESULT aQueueStatus[NUMBEROFPROPERTIES];
HRESULT hr = MQ_OK;
// Validate the input parameters.
if (wszPathName == NULL || wszOutFormatName == NULL || pdwOutFormatNameLength == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Set queue properties.
DWORD cPropId = 0;
aQueuePropId[cPropId] = PROPID_Q_PATHNAME;
aQueuePropVar[cPropId].vt = VT_LPWSTR;
aQueuePropVar[cPropId].pwszVal = wszPathName;
cPropId++;
WCHAR wszLabel[MQ_MAX_Q_LABEL_LEN] = L"Test Queue";
aQueuePropId[cPropId] = PROPID_Q_LABEL;
aQueuePropVar[cPropId].vt = VT_LPWSTR;
aQueuePropVar[cPropId].pwszVal = wszLabel;
cPropId++;
// Initialize the MQQUEUEPROPS structure.
QueueProps.cProp = cPropId; // Number of properties
QueueProps.aPropID = aQueuePropId; // IDs of the queue properties
QueueProps.aPropVar = aQueuePropVar; // Values of the queue properties
QueueProps.aStatus = aQueueStatus; // Pointer to the return status
// Call MQCreateQueue to create the queue.
WCHAR wszFormatNameBuffer[256];
DWORD dwFormatNameBufferLength = 256;
hr = MQCreateQueue(pSecurityDescriptor, // Security descriptor
&QueueProps, // Address of queue property structure
wszFormatNameBuffer, // Pointer to format name buffer
&dwFormatNameBufferLength); // Pointer to receive the queue's format name length in Unicode characters not bytes.
// Return the format name if the queue is created successfully.
if (hr == MQ_OK || hr == MQ_INFORMATION_PROPERTY)
{
if (*pdwOutFormatNameLength >= dwFormatNameBufferLength)
{
wcsncpy_s(wszOutFormatName, *pdwOutFormatNameLength - 1, wszFormatNameBuffer, _TRUNCATE);
wszOutFormatName[*pdwOutFormatNameLength - 1] = L'\0';
*pdwOutFormatNameLength = dwFormatNameBufferLength;
}
else
{
wprintf(L"The queue was created, but its format name cannot be returned.\n");
}
}
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout<<"started!";
LPWSTR sam = L".\\myQueue";
LPWSTR out_name = L"Sampleoutput";
DWORD d1 = 60;
DWORD *dd = &d1;
HRESULT hs = CreateMSMQQueue(sam,pt,out_name,dd);
return 0;
}
I didn't change much of the code. When I run this code, I get an "The application was unable to start correctly(0x0000142)" error. By debugging I found out tat its due to an "Memory access error" but there is no hint as to where it occurs. Please help me out!
Is there any format for queue names? Or the output format name ?
Related
I compiled IIS Native Module. If I compile 32bit and install in IIS. It gives error
The Module DLL ... failed to load. The data is the error. Data is 7E000000
If I compile 64 bit and install it in IIS, I have no error but module is not working.
I added code to write to log. When I use C:\Windows\System32\inetsrv\w3wp.exe in debugging property and debug it works and writes to log but when I use it in IIS neither RegisterModule is invoked, nor any of the notifications.
Any idea what may be wrong?
In Visual Studio elevated mode I can debug the dll just fine. Both 32 bit and 64 bit work just fine in debugging. It returns the data I want to return instead of returning actual page content. It is strange that same w3wp.exe running in IIS doesn't work with dll.
Update:
It works in Windows 7 IIS but doesn't work on Windows 10 IIS. Wondering what may be the difference.
main.cpp
#include "precomp.h"
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
// Global server instance
IHttpServer * g_pHttpServer = NULL;
// Global module context id
PVOID g_pModuleContext = NULL;
#define DTTMFMT "%Y-%m-%d %H:%M:%S "
#define DTTMSZ 21
static char* getDtTm(char* buff) {
time_t t = time(0);
strftime(buff, DTTMSZ, DTTMFMT, localtime(&t));
return buff;
}
// The RegisterModule entrypoint implementation.
// This method is called by the server when the module DLL is
// loaded in order to create the module factory,
// and register for server events.
HRESULT
__stdcall
RegisterModule(
DWORD dwServerVersion,
IHttpModuleRegistrationInfo * pModuleInfo,
IHttpServer * pHttpServer
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << " RegisterModule.\n";
myfile.close();
HRESULT hr = S_OK;
CJCFilterFactory * pFactory = NULL;
if ( pModuleInfo == NULL || pHttpServer == NULL )
{
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Finished;
}
// step 1: save the IHttpServer and the module context id for future use
g_pModuleContext = pModuleInfo->GetId();
g_pHttpServer = pHttpServer;
// step 2: create the module factory
pFactory = new CJCFilterFactory();
if ( pFactory == NULL )
{
hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
goto Finished;
}
// step 3: register for server events
// TODO: register for more server events here
hr = pModuleInfo->SetRequestNotifications( pFactory, /* module factory */
RQ_ACQUIRE_REQUEST_STATE | RQ_BEGIN_REQUEST/* server event mask */,
0 /* server post event mask */);
if ( FAILED( hr ) )
{
goto Finished;
}
// Set the request priority.
hr = pModuleInfo->SetPriorityForRequestNotification(
RQ_BEGIN_REQUEST, PRIORITY_ALIAS_FIRST);
if (FAILED(hr))
{
goto Finished;
}
pFactory = NULL;
Finished:
if ( pFactory != NULL )
{
delete pFactory;
pFactory = NULL;
}
return hr;
}
JCFilter.cpp
#include "precomp.h"
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
#define DTTMFMT "%Y-%m-%d %H:%M:%S "
#define DTTMSZ 21
static char* getDtTm(char* buff) {
time_t t = time(0);
strftime(buff, DTTMSZ, DTTMFMT, localtime(&t));
return buff;
}
// Implementation of the OnAcquireRequestState method
REQUEST_NOTIFICATION_STATUS
CJCFilter::OnAcquireRequestState(
IN IHttpContext * pHttpContext,
IN OUT IHttpEventProvider * pProvider
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << " OnAcquireRequestState.\n";
myfile.close();
HRESULT hr = S_OK;
// TODO: implement the AcquireRequestState module functionality
Finished:
if ( FAILED( hr ) )
{
return RQ_NOTIFICATION_FINISH_REQUEST;
}
else
{
return RQ_NOTIFICATION_CONTINUE;
}
}
REQUEST_NOTIFICATION_STATUS
CJCFilter::OnBeginRequest(
IN IHttpContext* pHttpContext,
IN IHttpEventProvider* pProvider
)
{
char buff[DTTMSZ];
ofstream myfile;
myfile.open("C:\\inetpub\\logs\\JCFilter.txt", ios::app);
myfile << getDtTm(buff);
myfile << "OnBeginRequest.\n";
myfile.close();
UNREFERENCED_PARAMETER(pProvider);
// Create an HRESULT to receive return values from methods.
HRESULT hr;
// Retrieve a pointer to the response.
IHttpResponse* pHttpResponse = pHttpContext->GetResponse();
// Test for an error.
if (pHttpResponse != NULL)
{
// Clear the existing response.
pHttpResponse->Clear();
// Set the MIME type to plain text.
pHttpResponse->SetHeader(
HttpHeaderContentType, "text/plain",
(USHORT)strlen("text/plain"), TRUE);
// Create a string with the response.
PCSTR pszBuffer = "Hello World!";
// Create a data chunk.
HTTP_DATA_CHUNK dataChunk;
// Set the chunk to a chunk in memory.
dataChunk.DataChunkType = HttpDataChunkFromMemory;
// Buffer for bytes written of data chunk.
DWORD cbSent;
// Set the chunk to the buffer.
dataChunk.FromMemory.pBuffer =
(PVOID)pszBuffer;
// Set the chunk size to the buffer size.
dataChunk.FromMemory.BufferLength =
(USHORT)strlen(pszBuffer);
// Insert the data chunk into the response.
hr = pHttpResponse->WriteEntityChunks(
&dataChunk, 1, FALSE, TRUE, &cbSent);
// Test for an error.
if (FAILED(hr))
{
// Set the HTTP status.
pHttpResponse->SetStatus(500, "Server Error", 0, hr);
}
// End additional processing.
return RQ_NOTIFICATION_FINISH_REQUEST;
}
// Return processing to the pipeline.
return RQ_NOTIFICATION_CONTINUE;
}
// TODO: implement other desired event handler methods below
I am trying to use SetPropertyItem to set a Date Taken property to a file (click here for MSDN docs description).
I have tried assigning a newly initialized FILETIME to an input image with no success (or error messages). To ensure that it was not an issue with Date Taken, I also tried following this MSDN example to no avail.
Currently, I am attempting to extract a Date Taken property item from one input file (works fine) and attempting to set it to a different file. This approach does not work either, and the Status code returned is always 0 (Ok).
The code I am using is below. I can only assume I am making a simple mistake or perhaps misunderstanding what SetPropertyItem is supposed to do. I thought that SetPropertyItem changed the metadata value such that it can be viewed through the Windows properties menu, like in this screenshot.
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#include <iostream>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Image* image = new Image(L"FakePhoto.jpg"); // input image
UINT totalBufferSize;
UINT numProperties; // setup the buffer
image->GetPropertySize(&totalBufferSize, &numProperties);
// extract all metadata property items
PropertyItem* pAllItems = (PropertyItem*)malloc(totalBufferSize);
image->GetAllPropertyItems(totalBufferSize, numProperties, pAllItems);
for (UINT j = 0; j < numProperties; ++j)
{ // loop through each property
if (pAllItems[j].id == PropertyTagExifDTOrig)
{ // if it's the Date Taken property
PropertyItem* propItem = new PropertyItem;
Image* newImage = new Image(L"Test2.jpg");
Status status; // second image
propItem->id = PropertyTagExifDTOrig;
propItem->length = pAllItems[j].length;
propItem->type = PropertyTagTypeASCII;
propItem->value = pAllItems[j].value;
// create a new property item with the input photo Date Taken metadata
status = newImage->SetPropertyItem(propItem);
if (status == Ok)
std::cout << "No errors.";
}
}
free(pAllItems);
delete image;
GdiplusShutdown(gdiplusToken);
}
Any help is greatly appreciated. Also, I apologise about any obvious/potential errors. I am still learning the ropes as this is my first time using C++.
You code works fine, but you must save the image back, for example like this
...
newImage->SetPropertyItem(propItem);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
newImage->Save(L"Test2.jpg", &clsid);
...
BOOL GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0;
UINT size = 0;
ImageCodecInfo* info = NULL;
ZeroMemory(pClsid, sizeof(CLSID));
GetImageEncodersSize(&num, &size);
if (size == 0)
return FALSE;
info = (ImageCodecInfo*)(malloc(size));
if (info == NULL)
return FALSE;
GetImageEncoders(num, size, info);
for (UINT j = 0; j < num; ++j)
{
if (!wcscmp(info[j].MimeType, format))
{
*pClsid = info[j].Clsid;
free(info);
return TRUE;
}
}
free(info);
return FALSE;
}
Using the same methods as in answers to other questions related to getting display names through WinApi (using EnumDisplayDevicesW while passing the device name as the first parameter, similarly to e.g. this one), I've been able to achieve partial success. The issue I'm having is that I'm getting incomplete information. The "Advanced display settings" panel which can be accessed by right clicking on the desktop, selecting "Display settings", and then selecting "Advanced display settings" on the bottom displays the following displays:
DELL P2414H(DisplayPort)
AOC AG271QG
BenQ PJ
However, through the use of EnumDisplayDevicesW calls, I extracted the following:
AOC AG271QG
DELL P2414H(DisplayPort)
Generic PnP Monitor
While the order doesn't matter to me, the issue is that I'm getting "Generic PnP Monitor" rather than the more helpful "BenQ PJ" (which is not the exact model that I was hoping for, but still provides at least some information). What can I do to extract "BenQ PJ" rather than "Generic PnP Monitor" (preferably remaining within WinApi)?
You can get Monitor information with EDID
EDID can be read with WMI
For example, test with WmiOpenBlock and so on, to reduce code of WMI in C++ =>
I get for my monitor :
Instance Name = DISPLAY\PHLC085\4&20634529&0&UID65793_0
User Friendly Name = 247ELH
Manufacturer Name = PHL
Product Code ID = C085
Serial Number ID = AU01307001613
Includes and defines =>
#define _CRT_NON_CONFORMING_SWPRINTFS
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <tchar.h>
#include <initguid.h>
#include <wmistr.h>
DEFINE_GUID(WmiMonitorID_GUID, 0x671a8285, 0x4edb, 0x4cae, 0x99,0xfe,0x69,0xa1,0x5c,0x48,0xc0,0xbc );
typedef struct WmiMonitorID {
USHORT ProductCodeID[16];
USHORT SerialNumberID[16];
USHORT ManufacturerName[16];
UCHAR WeekOfManufacture;
USHORT YearOfManufacture;
USHORT UserFriendlyNameLength;
USHORT UserFriendlyName[1];
} WmiMonitorID, *PWmiMonitorID;
#define OFFSET_TO_PTR(Base, Offset) ((PBYTE)((PBYTE)Base + Offset))
typedef HRESULT(WINAPI*WOB) (IN LPGUID lpGUID, IN DWORD nAccess, OUT LONG*);
WOB WmiOpenBlock;
typedef HRESULT(WINAPI*WQAD) (IN LONG hWMIHandle, ULONG* nBufferSize, OUT UCHAR * pBuffer);
WQAD WmiQueryAllData;
typedef HRESULT(WINAPI*WCB) (IN LONG);
WCB WmiCloseBlock;
Test code =>
HRESULT hr = E_FAIL;
LONG hWmiHandle;
PWmiMonitorID MonitorID;
HINSTANCE hDLL = LoadLibrary(L"Advapi32.dll");
WmiOpenBlock = (WOB)GetProcAddress(hDLL, "WmiOpenBlock");
WmiQueryAllData = (WQAD)GetProcAddress(hDLL, "WmiQueryAllDataW");
WmiCloseBlock = (WCB)GetProcAddress(hDLL, "WmiCloseBlock");
if (WmiOpenBlock != NULL && WmiQueryAllData && WmiCloseBlock)
{
WCHAR pszDeviceId[256] = L"";
hr = WmiOpenBlock((LPGUID)&WmiMonitorID_GUID, GENERIC_READ, &hWmiHandle);
if (hr == ERROR_SUCCESS)
{
ULONG nBufferSize = 0;
UCHAR *pAllDataBuffer = 0;
PWNODE_ALL_DATA pWmiAllData;
hr = WmiQueryAllData(hWmiHandle, &nBufferSize, 0);
if (hr == ERROR_INSUFFICIENT_BUFFER)
{
pAllDataBuffer = (UCHAR*)malloc(nBufferSize);
hr = WmiQueryAllData(hWmiHandle, &nBufferSize, pAllDataBuffer);
if (hr == ERROR_SUCCESS)
{
while (1)
{
pWmiAllData = (PWNODE_ALL_DATA)pAllDataBuffer;
if (pWmiAllData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE)
MonitorID = (PWmiMonitorID)&pAllDataBuffer[pWmiAllData->DataBlockOffset];
else
MonitorID = (PWmiMonitorID)&pAllDataBuffer[pWmiAllData->OffsetInstanceDataAndLength[0].OffsetInstanceData];
ULONG nOffset = 0;
WCHAR *pwsInstanceName = 0;
nOffset = (ULONG)pAllDataBuffer[pWmiAllData->OffsetInstanceNameOffsets];
pwsInstanceName = (WCHAR*)OFFSET_TO_PTR(pWmiAllData, nOffset + sizeof(USHORT));
WCHAR wsText[255] = L"";
swprintf(wsText, L"Instance Name = %s\r\n", pwsInstanceName);
OutputDebugString(wsText);
WCHAR *pwsUserFriendlyName;
pwsUserFriendlyName = (WCHAR*)MonitorID->UserFriendlyName;
swprintf(wsText, L"User Friendly Name = %s\r\n", pwsUserFriendlyName);
OutputDebugString(wsText);
WCHAR *pwsManufacturerName;
pwsManufacturerName = (WCHAR*)MonitorID->ManufacturerName;
swprintf(wsText, L"Manufacturer Name = %s\r\n", pwsManufacturerName);
OutputDebugString(wsText);
WCHAR *pwsProductCodeID;
pwsProductCodeID = (WCHAR*)MonitorID->ProductCodeID;
swprintf(wsText, L"Product Code ID = %s\r\n", pwsProductCodeID);
OutputDebugString(wsText);
WCHAR *pwsSerialNumberID;
pwsSerialNumberID = (WCHAR*)MonitorID->SerialNumberID;
swprintf(wsText, L"Serial Number ID = %s\r\n", pwsSerialNumberID);
OutputDebugString(wsText);
if (!pWmiAllData->WnodeHeader.Linkage)
break;
pAllDataBuffer += pWmiAllData->WnodeHeader.Linkage;
}
free(pAllDataBuffer);
}
}
WmiCloseBlock(hWmiHandle);
}
}
I am currently working on a C++ application that will read the message from the MSMQ.....
this is the code that I ran :
HRESULT ReadingDestQueue(
WCHAR * wszQueueName,
WCHAR * wszComputerName
)
{
// Define the required constants and variables.
const int NUMBEROFPROPERTIES = 5;
DWORD cPropId = 0;
HRESULT hr = MQ_OK; // Return code
HANDLE hQueue = NULL; // Queue handle
ULONG ulBufferSize = 2;
// Define an MQMSGPROPS structure.
MQMSGPROPS msgprops;
MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];
MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];
HRESULT aMsgStatus[NUMBEROFPROPERTIES];
// Specify the message properties to be retrieved.
aMsgPropId[cPropId] = PROPID_M_LABEL_LEN; // Property ID
aMsgPropVar[cPropId].vt = VT_UI4; // Type indicator
aMsgPropVar[cPropId].ulVal = MQ_MAX_MSG_LABEL_LEN; // Length of label
cPropId++;
WCHAR wszLabelBuffer[MQ_MAX_MSG_LABEL_LEN]; // Label buffer
aMsgPropId[cPropId] = PROPID_M_LABEL; // Property ID
aMsgPropVar[cPropId].vt = VT_LPWSTR; // Type indicator
aMsgPropVar[cPropId].pwszVal = wszLabelBuffer; // Label buffer
cPropId++;
UCHAR * pucBodyBuffer = NULL;
pucBodyBuffer = (UCHAR*)malloc(ulBufferSize);
if (pucBodyBuffer == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(pucBodyBuffer, 0, ulBufferSize);
aMsgPropId[cPropId] = PROPID_M_BODY_SIZE; // Property ID
aMsgPropVar[cPropId].vt = VT_NULL; // Type indicator
cPropId++;
aMsgPropId[cPropId] = PROPID_M_BODY; // Property ID
aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1; // Type indicator
aMsgPropVar[cPropId].caub.pElems = (UCHAR*)pucBodyBuffer; // Body buffer
aMsgPropVar[cPropId].caub.cElems = ulBufferSize; // Buffer size
cPropId++;
aMsgPropId[cPropId] = PROPID_M_BODY_TYPE; // Property ID
aMsgPropVar[cPropId].vt = VT_NULL; // Type indicator
cPropId++;
// Initialize the MQMSGPROPS structure.
msgprops.cProp = cPropId; // Number of message properties
msgprops.aPropID = aMsgPropId; // IDs of the message properties
msgprops.aPropVar = aMsgPropVar; // Values of the message properties
msgprops.aStatus = aMsgStatus; // Error reports
// Validate the input strings.
if (wszQueueName == NULL || wszComputerName == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Create a direct format name.
WCHAR * wszFormatName = NULL;
DWORD dwFormatNameLength = 0;
dwFormatNameLength = wcslen(wszQueueName) + wcslen(wszComputerName) + 12;
wszFormatName = new WCHAR[dwFormatNameLength];
if (wszFormatName == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(wszFormatName, 0, dwFormatNameLength);
// ************************************
// You must concatenate "DIRECT=OS:", wszComputerName, "\",
// and wszQueueName into the wszFormatName buffer.
// wszFormatName = "DIRECT=OS:" + wszComputerName + "\" +
// wszQueueName
// If the format name is too long for the buffer, return FALSE.
// ************************************
// Open the queue with receive access.
hr = MQOpenQueue(
wszFormatName, // Format name of the queue
MQ_RECEIVE_ACCESS, // Access mode
MQ_DENY_NONE, // Share mode
&hQueue // OUT: Queue handle
);
// Free the memory that was allocated for the format name string.
if (wszFormatName)
{
delete[] wszFormatName;
}
// Handle any error returned by MQOpenQueue.
if (FAILED(hr))
{
return hr;
}
for (; ; )
{
aMsgPropVar[0].ulVal = MQ_MAX_MSG_LABEL_LEN;
hr = MQReceiveMessage(
hQueue, // Queue handle
1000, // Max time to (msec) to receive the message
MQ_ACTION_RECEIVE, // Receive action
&msgprops, // Message property structure
NULL, // No OVERLAPPED structure
NULL, // No callback function
NULL, // No cursor handle
MQ_NO_TRANSACTION // Not in a transaction
);
if (hr == MQ_ERROR_BUFFER_OVERFLOW)
{
ulBufferSize = aMsgPropVar[2].ulVal * sizeof(UCHAR);
pucBodyBuffer = (UCHAR*)realloc(pucBodyBuffer, ulBufferSize);
if (pucBodyBuffer == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(pucBodyBuffer, 0, ulBufferSize);
aMsgPropVar[3].caub.pElems = (UCHAR*)pucBodyBuffer;
aMsgPropVar[3].caub.cElems = ulBufferSize;
continue;
}
if (FAILED(hr))
{
wprintf(L"No messages. Closing queue\n");
break;
}
// If the message contains a label, print it.
if (msgprops.aPropVar[0].ulVal == 0)
{
wprintf(L"Removed message from queue.\n");
}
else
{
wprintf(L"Removed message '%s' from queue.\n", wszLabelBuffer);
}
// If the message body is a string, display it.
if (msgprops.aPropVar[4].ulVal == VT_BSTR)
{
wprintf(L"Body: %s", (WCHAR*)pucBodyBuffer);
wprintf(L"\n");
}
}
// Close the queue and free the memory allocated for the body buffer.
hr = MQCloseQueue(hQueue);
free(pucBodyBuffer);
return hr;
}
int main()
{
WCHAR wszComputerName =(WCHAR)L"wsm-ela-inc5";
WCHAR wszQueueName = (WCHAR)L"private$\\soorya1";
_com_error err(ReadingDestQueue(&wszQueueName, &wszComputerName));
LPCTSTR errMsg = err.ErrorMessage();
wcout << errMsg;
return 0;
}
this is my MSMQ queue :
when I run this...I am getting an error code of "0xC00E001E" (MQ_ERROR_ILLEGAL_FORMATNAME (0xC00E001E)
Returned when the specified format name is not valid)
any methods to recover this?
Passing the format name itself did the trick!
here is the code :
// ReadMsg.cpp : Defines the entry point for the console application.
//
#define _CRT_SECURE_NO_DEPRECATE
#include "stdafx.h"
#include "windows.h"
#include "mq.h"
#include "tchar.h"
#include"comdef.h"
#include"iostream"
using namespace std;
HRESULT ReadingDestQueue( LPWSTR lpwcsFormatName)
{
// Define the required constants and variables.
const int NUMBEROFPROPERTIES = 5;
DWORD cPropId = 0;
HRESULT hr = MQ_OK; // Return code
HANDLE hQueue = NULL; // Queue handle
ULONG ulBufferSize = 2;
// Define an MQMSGPROPS structure.
MQMSGPROPS msgprops;
MSGPROPID aMsgPropId[NUMBEROFPROPERTIES];
MQPROPVARIANT aMsgPropVar[NUMBEROFPROPERTIES];
HRESULT aMsgStatus[NUMBEROFPROPERTIES];
// Specify the message properties to be retrieved.
aMsgPropId[cPropId] = PROPID_M_LABEL_LEN; // Property ID
aMsgPropVar[cPropId].vt = VT_UI4; // Type indicator
aMsgPropVar[cPropId].ulVal = MQ_MAX_MSG_LABEL_LEN; // Length of label
cPropId++;
WCHAR wszLabelBuffer[MQ_MAX_MSG_LABEL_LEN]; // Label buffer
aMsgPropId[cPropId] = PROPID_M_LABEL; // Property ID
aMsgPropVar[cPropId].vt = VT_LPWSTR; // Type indicator
aMsgPropVar[cPropId].pwszVal = wszLabelBuffer; // Label buffer
cPropId++;
UCHAR * pucBodyBuffer = NULL;
pucBodyBuffer = (UCHAR*)malloc(ulBufferSize);
if (pucBodyBuffer == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(pucBodyBuffer, 0, ulBufferSize);
aMsgPropId[cPropId] = PROPID_M_BODY_SIZE; // Property ID
aMsgPropVar[cPropId].vt = VT_NULL; // Type indicator
cPropId++;
aMsgPropId[cPropId] = PROPID_M_BODY; // Property ID
aMsgPropVar[cPropId].vt = VT_VECTOR | VT_UI1; // Type indicator
aMsgPropVar[cPropId].caub.pElems = (UCHAR*)pucBodyBuffer; // Body buffer
aMsgPropVar[cPropId].caub.cElems = ulBufferSize; // Buffer size
cPropId++;
aMsgPropId[cPropId] = PROPID_M_BODY_TYPE; // Property ID
aMsgPropVar[cPropId].vt = VT_NULL; // Type indicator
cPropId++;
// Initialize the MQMSGPROPS structure.
msgprops.cProp = cPropId; // Number of message properties
msgprops.aPropID = aMsgPropId; // IDs of the message properties
msgprops.aPropVar = aMsgPropVar; // Values of the message properties
msgprops.aStatus = aMsgStatus; // Error reports
// Validate the input strings.
if (lpwcsFormatName == NULL)
{
return MQ_ERROR_INVALID_PARAMETER;
}
// Open the queue with receive access.
hr = MQOpenQueue(
lpwcsFormatName, // Format name of the queue
MQ_RECEIVE_ACCESS, // Access mode
MQ_DENY_NONE, // Share mode
&hQueue // OUT: Queue handle
);
// Handle any error returned by MQOpenQueue.
if (FAILED(hr))
{
return hr;
}
while(1)
{
aMsgPropVar[0].ulVal = MQ_MAX_MSG_LABEL_LEN;
hr = MQReceiveMessage(
hQueue, // Queue handle
1000, // Max time to (msec) to receive the message
MQ_ACTION_RECEIVE, // Receive action
&msgprops, // Message property structure
NULL, // No OVERLAPPED structure
NULL, // No callback function
NULL, // No cursor handle
MQ_NO_TRANSACTION // Not in a transaction
);
if (hr == MQ_ERROR_BUFFER_OVERFLOW)
{
ulBufferSize = aMsgPropVar[2].ulVal * sizeof(UCHAR);
pucBodyBuffer = (UCHAR*)realloc(pucBodyBuffer, ulBufferSize);
if (pucBodyBuffer == NULL)
{
return MQ_ERROR_INSUFFICIENT_RESOURCES;
}
memset(pucBodyBuffer, 0, ulBufferSize);
aMsgPropVar[3].caub.pElems = (UCHAR*)pucBodyBuffer;
aMsgPropVar[3].caub.cElems = ulBufferSize;
continue;
}
if (FAILED(hr))
{
wprintf(L"No messages. Closing queue\n");
break;
}
// If the message contains a label, print it.
if (msgprops.aPropVar[0].ulVal == 0)
{
wprintf(L"Removed message from queue.\n");
}
else
{
wprintf(L"Removed message '%s' from queue.\n", (char *)wszLabelBuffer);
//cout << "Removed message ";
//wcout << wszLabelBuffer;
//cout << "from queue.\n";
}
// If the message body is a string, display it.
if (msgprops.aPropVar[4].ulVal == VT_BSTR)
{
wprintf(L"Body: %s", (WCHAR*)pucBodyBuffer);
wprintf(L"\n");
}
}
// Close the queue and free the memory allocated for the body buffer.
hr = MQCloseQueue(hQueue);
free(pucBodyBuffer);
return hr;
}
int main()
{
LPWSTR lpwcsFormatName = (LPWSTR)L"DIRECT=OS:wsm-ela-inc5\\private$\\soorya97";
_com_error err(ReadingDestQueue(lpwcsFormatName));
LPCTSTR errMsg = err.ErrorMessage();
wcout << errMsg << endl;
return 0;
}
Given a handle to a Windows Registry Key, such as the ones that are set by ::RegOpenKeyEx(), is it possible to determine the full path to that key?
I realize that in a simple application all you have to do is look up 5 or 10 lines and read... but in a complex app like the one I'm debugging, the key I'm interested in can be opened from a series of calls.
Use LoadLibrary and NtQueryKey exported function as in the following code snippet.
#include <windows.h>
#include <string>
typedef LONG NTSTATUS;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#ifndef STATUS_BUFFER_TOO_SMALL
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#endif
std::wstring GetKeyPathFromKKEY(HKEY key)
{
std::wstring keyPath;
if (key != NULL)
{
HMODULE dll = LoadLibrary(L"ntdll.dll");
if (dll != NULL) {
typedef DWORD (__stdcall *NtQueryKeyType)(
HANDLE KeyHandle,
int KeyInformationClass,
PVOID KeyInformation,
ULONG Length,
PULONG ResultLength);
NtQueryKeyType func = reinterpret_cast<NtQueryKeyType>(::GetProcAddress(dll, "NtQueryKey"));
if (func != NULL) {
DWORD size = 0;
DWORD result = 0;
result = func(key, 3, 0, 0, &size);
if (result == STATUS_BUFFER_TOO_SMALL)
{
size = size + 2;
wchar_t* buffer = new (std::nothrow) wchar_t[size/sizeof(wchar_t)]; // size is in bytes
if (buffer != NULL)
{
result = func(key, 3, buffer, size, &size);
if (result == STATUS_SUCCESS)
{
buffer[size / sizeof(wchar_t)] = L'\0';
keyPath = std::wstring(buffer + 2);
}
delete[] buffer;
}
}
}
FreeLibrary(dll);
}
}
return keyPath;
}
int _tmain(int argc, _TCHAR* argv[])
{
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
ret = RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft", &key);
if (ret == ERROR_SUCCESS)
{
wprintf_s(L"Key path for %p is '%s'.", key, GetKeyPathFromKKEY(key).c_str());
RegCloseKey(key);
}
return 0;
}
This will print the key path on the console:
Key path for 00000FDC is
'\REGISTRY\MACHINE\SOFTWARE\Microsoft'.
I was excited to find this article and its well liked solution.
Until I found that my system's NTDLL.DLL did not have NtQueryKeyType.
After some hunting around, I ran across ZwQueryKey in the DDK forums.
It is in C#, but here is the solution that works for me:
enum KEY_INFORMATION_CLASS
{
KeyBasicInformation, // A KEY_BASIC_INFORMATION structure is supplied.
KeyNodeInformation, // A KEY_NODE_INFORMATION structure is supplied.
KeyFullInformation, // A KEY_FULL_INFORMATION structure is supplied.
KeyNameInformation, // A KEY_NAME_INFORMATION structure is supplied.
KeyCachedInformation, // A KEY_CACHED_INFORMATION structure is supplied.
KeyFlagsInformation, // Reserved for system use.
KeyVirtualizationInformation, // A KEY_VIRTUALIZATION_INFORMATION structure is supplied.
KeyHandleTagsInformation, // Reserved for system use.
MaxKeyInfoClass // The maximum value in this enumeration type.
}
[StructLayout(LayoutKind.Sequential)]
public struct KEY_NAME_INFORMATION
{
public UInt32 NameLength; // The size, in bytes, of the key name string in the Name array.
public char[] Name; // An array of wide characters that contains the name of the key.
// This character string is not null-terminated.
// Only the first element in this array is included in the
// KEY_NAME_INFORMATION structure definition.
// The storage for the remaining elements in the array immediately
// follows this element.
}
[DllImport("ntdll.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern int ZwQueryKey(IntPtr hKey, KEY_INFORMATION_CLASS KeyInformationClass, IntPtr lpKeyInformation, int Length, out int ResultLength);
public static String GetHKeyName(IntPtr hKey)
{
String result = String.Empty;
IntPtr pKNI = IntPtr.Zero;
int needed = 0;
int status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, IntPtr.Zero, 0, out needed);
if ((UInt32)status == 0xC0000023) // STATUS_BUFFER_TOO_SMALL
{
pKNI = Marshal.AllocHGlobal(sizeof(UInt32) + needed + 4 /*paranoia*/);
status = ZwQueryKey(hKey, KEY_INFORMATION_CLASS.KeyNameInformation, pKNI, needed, out needed);
if (status == 0) // STATUS_SUCCESS
{
char[] bytes = new char[2 + needed + 2];
Marshal.Copy(pKNI, bytes, 0, needed);
// startIndex == 2 skips the NameLength field of the structure (2 chars == 4 bytes)
// needed/2 reduces value from bytes to chars
// needed/2 - 2 reduces length to not include the NameLength
result = new String(bytes, 2, (needed/2)-2);
}
}
Marshal.FreeHGlobal(pKNI);
return result;
}
I've only ever tried it while running as Administrator, which may be required.
The result is a bit oddly formatted: \REGISTRY\MACHINE\SOFTWARE\company\product for example, instead of HKEY_LOCAL_MACHINE\SOFTWARE\company\product.
Nominally no because it's just a handle and there is no API that I know of to let you do this in the normal Windows API's.
HOWEVER the Native API has lots of functions some of which can give you handles open for given files and the like so there maybe something similar for the Registry. That and RegMon by SysInternals may do something like this but you'll have to Google I'm afraid :/
You can use RegSaveKey and write it to a file, then look at the file.
Alternatively you can keep a global map of HKEYs to LPCWSTRs and add entries when you open them and do lookups whenever.
You may also be able to do something with the !reg command in WinDBG / NTSD, but you can't just give it the HKEY. You'll have to do some other trickery to get the info you want out of it.
Since std::wstring allows to construct string from pointer and count of characters, and the kernel string always return the count of bytes, it is not necessary to terminated the string with NUL. I do not suggest that to add size or to offset the pointer by constant number directly, it's better to use the real data type like the structure types instead, and std::vector<UCHAR> instead of new for dynamic memory allocating. I modified the code from highly upvoted answer as the followings.
The legacy way, obtaining the function pointer from ntdll.dll dynamically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
typedef NTSTATUS (NTAPI *PFN_NtQueryKey)(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
if (hKey != NULL)
{
HMODULE hinstDLL = GetModuleHandleW(L"ntdll.dll");
if (hinstDLL != NULL)
{
FARPROC pfn = GetProcAddress(hinstDLL, "NtQueryKey");
if (pfn != NULL)
{
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = reinterpret_cast<PFN_NtQueryKey>(pfn)(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
}
}
}
return keyPath;
}
If you are using Visual Studio 2015 or above, ntdll.lib is included by default, so I suggest that linking to ntdll.dll statically:
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
#include <string>
#include <vector>
#define REG_KEY_PATH_LENGTH 1024
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
KeyNodeInformation,
KeyFullInformation,
KeyNameInformation,
KeyCachedInformation,
KeyFlagsInformation,
KeyVirtualizationInformation,
KeyHandleTagsInformation,
KeyTrustInformation,
KeyLayerInformation,
MaxKeyInfoClass
} KEY_INFORMATION_CLASS;
typedef struct _KEY_NAME_INFORMATION {
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
EXTERN_C NTSYSAPI NTSTATUS NTAPI NtQueryKey(
__in HANDLE /* KeyHandle */,
__in KEY_INFORMATION_CLASS /* KeyInformationClass */,
__out_opt PVOID /* KeyInformation */,
__in ULONG /* Length */,
__out ULONG * /* ResultLength */
);
std::wstring RegQueryKeyPath(HKEY hKey)
{
std::wstring keyPath;
NTSTATUS Status;
std::vector<UCHAR> Buffer(FIELD_OFFSET(KEY_NAME_INFORMATION, Name) + sizeof(WCHAR) * REG_KEY_PATH_LENGTH);
KEY_NAME_INFORMATION *pkni;
ULONG Length;
TryAgain:
Status = NtQueryKey(hKey, KeyNameInformation, Buffer.data(), Buffer.size(), &Length);
switch (Status) {
case STATUS_BUFFER_TOO_SMALL:
case STATUS_BUFFER_OVERFLOW:
Buffer.resize(Length);
goto TryAgain;
case STATUS_SUCCESS:
pkni = reinterpret_cast<KEY_NAME_INFORMATION *>(Buffer.data());
keyPath.assign(pkni->Name, pkni->NameLength / sizeof(WCHAR));
default:
break;
}
return keyPath;
}
Note that NtQueryKey returned STATUS_BUFFER_OVERFLOW but not STATUS_BUFFER_TOO_SMALL on Windows 10 if the supplied buffer is insufficient.
For ntsd/windbg:
!handle yourhandle 4