|
I am trying to read
information of the SMS Status system. My problem is extracting the full text
description field. (That is what you can read from the SMS Status system).
From what I can gather I need to use the FormatMessage API call - however I
cannot find what and how to pass the parameters to this function.
Extract: from:
http://msdn.microsoft.com/library/en-us/sms/hh/sms/usingsms_2sz7.asp
Reading Raw Messages
The message text for both the SMS components and the raw user-defined
messages is contained in message DLLs. The SMS_StatMsgInsStrings class
contains the insertion strings for those messages that use insertion
strings. To read the SMS component and raw user-defined messages, you must
know the message DLL that contains the message text.
You can get the DLL name from the SMS_StatMsgModuleNames class. The
SMS_StatMsgModuleNames class contains the ModuleName and the MsgDLLName
properties. You can use ModuleName to join the SMS_StatMsgModuleNames class
with the SMS_StatusMessage class, as the following example shows.
// Note that this query returns all the instances found in the
SMS_Status_Message // class. This query can return several thousand
instances. If you test this // query, you should add a where clause to limit
its scope, or set the // InstanceCount context qualifier to limit the number
of instances returned.
SELECT B.Severity,
B.MessageID, B.MessageType,
B.Win32Error, B.SiteCode, B.MachineName,
B.Component, C.MsgDLLName, D.InsStrValue FROM SMS_StatusMessage AS B
INNER JOIN SMS_StatMsgModuleNames AS C
ON B.ModuleName = C.ModuleName
LEFT OUTER JOIN SMS_StatMsgInsStrings AS D
ON B.RecordID = D.RecordID
ORDER BY B.Sitecode, B.RecordID, B.MessageID, D.InsStrIndex
The Microsoft
BackOffice Resource Kit contains the list of SMS component-generated
messages. You can use the MessageID and Component names from the list to
limit your status message query. For example, you can add a WHERE clause to
limit the status messages to the SMS_Distribution_Manager component.
After you have the DLL name, you can use the Microsoft® Win32® API function
FormatMessage to retrieve the message text from the component's message DLL.
This requires you to get the module handle for the DLL using the Win32 API
function, GetModuleHandle. The dwMessageId parameter is the OR'd result of
the MessageID and the Severity properties. You should set the
FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass the insertion strings as an
array.
The following code fragment shows you how to call FormatMessage to retrieve
the message text from a DLL.
// Get the module
handle for the component's message DLL. This assumes the // message DLL is
loaded. If the DLL is not loaded, then load the DLL using // the Win32 API
LoadLibrary.
hmodMessageDLL =
GetModuleHandle(MsgDLLName);
// The flags tell
FormatMessage to allocate the memory needed for the message, // to get the
message text from a message DLL, and that the insertion strings are //
stored in an array, instead of a variable length argument list. The last //
parameter, apInsertStrings, is the array of insertion strings returned by
the // query.
dwMsgLen =
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
hmodMessageDLL,
Severity | MessageID,
0,
lpBuffer,
nSize,
apInsertStrings);
// Free the memory
after you use the message text.
LocalFree(lpBuffer);
===============================================================
Question is on this --
how do I populate apInsertStrings? Does anybody have any ideas on this
- or even some sample code.
Contributed By: Russ Wilson [MS]
The app insert
strings are the argument values that will replace the substitution
parameters in the fixed string from the resource dll. So the string from
the dll will read something like 'error in package ID %s' and the value for
the string will be in the apInsertStrings. You probably knew that. So the
insertion strings are stored in a different class (table) which is in the
query as SMS_StatMsgInsStrings . The trouble is you need to get the results
into a string array. So each instance from the returned query below will
have D.InsStrValue as a single string value. You need to collect these
together for each unique record ID and put them into a string array then
pass that in as apInsertStrings.
Something like
WCHAR* apInsertStrings[3];
apInsertStrings[0] =
first instance string apInsertStrings[1] = second string apInsertStrings[2]
= NULL;
Arguments
[in] Pointer to an array of 32-bit values that are used as insert values in
the formatted message. A %1 in the format string indicates the first value
in the Arguments array; a %2 indicates the second argument; and so on.
The interpretation of each 32-bit value depends on the formatting
information associated with the insert in the message definition. The
default is to treat each value as a pointer to a null-terminated string.
By default, the Arguments parameter is of type va_list*, which is a
language- and implementation-specific data type for describing a variable
number of arguments. If you do not have a pointer of type va_list*, then
specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an
array of 32-bit values; those values are input to the message formatted as
the insert values. Each insert must have a corresponding element in the
array.
Full description of FormatMessage on MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcesdk40/htm/cerefformatmessage.asp
|