I am developing an application in C++ using VS2010. In my code,I have two WQL queries as follows:
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * "
"FROM __InstanceDeletionEvent WITHIN 1 "
"WHERE TargetInstance ISA 'Win32_Process' "),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
hres1 = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * "
"FROM __InstanceCreationEvent WITHIN 1 "
"WHERE TargetInstance ISA 'Win32_Process'"),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
On cretion or deletion of processes I get its name printed into the console from the IWbemObjectSink::Indicate method. When the name of the process is printed, I need to know whether it was created or deleted. How will I know this? Is there some way to know which asynchronous method made the call to Indicate method?
Thankyou
__InstanceDeletionEvent and __InstanceCreationEvent are subclasses of __InstanceOperationEvent. Hence, you should be querying for instances of __InstanceOperationEvent. Then you will Get the Class from the object in your Sink Class (e.g., pStubSink) to know from which instance is being created. Look at this example to get an idea about how to handle a similar situation: http://blogs.technet.com/b/heyscriptingguy/archive/2005/04/04/how-can-i-monitor-for-different-types-of-events-with-just-one-script.aspx
UPDATE1:
__InstanceOperationEvent is superclass of: __InstanceDeletionEvent, __InstanceCreationEvent and __InstanceModificationEvent.
pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE Targetinstance ISA 'Win32_Process'"),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
In your Indicate function:
Indicate(long lObjectCount,
IWbemClassObject **apObjArray)
{
HRESULT hr = S_OK;
for (int i = 0; i < lObjectCount; i++)
{
_variant_t myVariant;
hr = apObjArray[i]->Get(_bstr_t(L"__Class"), 0, &myVariant, 0, 0);
if (SUCCEEDED(hr))
{
std::wstring classOrigin(myVariant.bstrVal);
if (0 == classOrigin.compare(L"__InstanceDeletionEvent") )
{
std::wcout << L"DELETION" << std::endl;
}
else if (0 == classOrigin.compare(L"__InstanceCreationEvent"))
{
std::wcout << L"CREATION" << std::endl;
}
}
}
}
myVariant will say which is the class that generated the event (read note).
NOTE: This will result in a constant call to your pStubSink because Processes are constantly being modificated (__InstanceModificationEvent, e.g., changes in memory/CPU).
UPDATE2: You could also have two different Queries (and consecuently Sink objects), one for creation and one for deletion (e.g., pStubSinkCreation, pStubSinkDeletion). In this way you (1) would know exactly when it comes from Creation and when from Deletion; and (2) would avoid to be receiving constantly the __InstanceModificationEvent.
Related
Here is the minimal code for reference
ULONG result = GetSecurityInfo(Hfile
, SE_FILE_OBJECT
, OWNER_SECURITY_INFORMATION |GROUP_SECURITY_INFORMATION| DACL_SECURITY_INFORMATION
, &sidowner
, &sidgroup
, &pdacl
, NULL
, &psd);
This is how I extracted the access control entries from DACL
BOOL b = GetAce(pdacl, i, (LPVOID*)&ace);
if (((ACCESS_ALLOWED_ACE*)ace)->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
sid = (PSID)&((ACCESS_ALLOWED_ACE*)ace)->SidStart;
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
mask = ((ACCESS_ALLOWED_ACE*)ace)->Mask;
cout << "Allowed" << endl;
}
output:
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
WRITE_DAC
WRITE_OWNER
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Administrators
Allowed
DELETE
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
domianName/AccoutName : BUILTIN/Users
Allowed
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
READ_CONTROL
SYNCHRONIZE
As we can see from the above output Administrators have multiple entries and ACE of "System" and "Authenticated users" are not found. "Users" only have read rights in file properties but in the output, it is printed that the "Users" have "Write access" as well.
I did a lot of research and read through many books but nothing seems to give a clear-cut answer
edit:
Here's the output using the CACLS command.
C:\Users\Administrator>cacls e:/hello.txt
e:\hello.txt BUILTIN\Administrators:F
NT AUTHORITY\SYSTEM:F
NT AUTHORITY\Authenticated Users:C
BUILTIN\Users:R
The first part of the question:
The reason why the program prints the name same account name repeatedly is because the LookupAccountSid function does not have enough data area. since the namelen and domainlen are IN\OUT arguments the function returns the size of the domain name and account name every time after execution. So to solve this the namelen and domainlen have to be reassigned every time.
LookupAccountSid(NULL, sid, oname, &namelen, doname, &domainnamelen, &peUse);
wcout << "domianName/AccoutName : " << doname << "/" << oname << endl;
namelen = 100; domainnamelen = 100; //This should solve the problem
Here is the link to the docs for the LookupAccountSid function
The second part of the question
The reason why the output from the program shows the users have FILE_GENERIC_WRITE permission even though the CACLS seem to show that users only have read and execute permission to the given file path is that in the program the code that checks if the users have the write permissions is done by the following.
if (FILE_GENERIC_WRITE & ace->Mask) {
wcout << " FILE_GENERIC_WRITE" << "\n";
}
The problem is the FILE_GENERIC_WRITE consists of multiple permissions like STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE and when the code is written like this (FILE_GENERIC_WRITE & ace->Mask) it only checks if at least one of the permissions is present or not.
A special thanks to #user253751 and #Werner Henze for patiently explaining the solution
I try to receive the numer of records for a Select statement and the record set at once.
The Recordset Object offers the RecordCount Property for this issue.
It works just fine using a static, server-side cursor, but if i view the events in SQL Server Profiler, I realize, that it seems to fetch every row of the whole recordset, just to count the rows.
On the other hand, I can do a MoveLast on the recordset and the Bookmark contains the index of the last row (== Recordcount).
I do not want to use the Bookmark instead of the RecordCount and wonder if someone could explain this behaviour.
If anyone is interessted, I created a small code sample to reproduce it:
::CoInitialize(NULL);
ADODB::_ConnectionPtr pConn;
HRESULT hr;
hr = pConn.CreateInstance(__uuidof(ADODB::Connection));
pConn->CursorLocation = ADODB::adUseServer;
pConn->ConnectionTimeout = 0;
pConn->Provider = "SQLOLEDB";
pConn->Open(bstr_t("Provider=sqloledb;Data Source=s11;Initial Catalog=...;Application Name=DBTEST"), "", "", ADODB::adConnectUnspecified);
// Create Command Object
_variant_t vtRecordsAffected;
ADODB::_CommandPtr cmd;
hr = cmd.CreateInstance(__uuidof(ADODB::Command));
cmd->ActiveConnection = pConn;
cmd->CommandTimeout = 0;
// Create a test table
cmd->CommandText = _bstr_t("create table #mytestingtab (iIdentity INT)");
cmd->Execute(&vtRecordsAffected, NULL, ADODB::adCmdText);
// Populate
cmd->CommandText = _bstr_t(
"DECLARE #iNr INT\r\n"
"SET #iNr = 0\r\n"
"WHILE #iNr < 10000\r\n"
"BEGIN\r\n"
" INSERT INTO #mytestingtab (iIdentity) VALUES (#iNr)\r\n"
" SET #iNr = #iNr + 1\r\n"
"END\r\n"
);
cmd->Execute(&vtRecordsAffected, NULL, ADODB::adCmdText);
// Create a Recordset Object
_variant_t vtEmpty(DISP_E_PARAMNOTFOUND, VT_ERROR);
ADODB::_RecordsetPtr Recordset;
hr = Recordset.CreateInstance(__uuidof(ADODB::Recordset));
Recordset->CursorLocation = ADODB::adUseServer;
cmd->CommandText = _bstr_t(
"SELECT * FROM #mytestingtab"
);
Recordset->PutRefSource(cmd);
Recordset->Open(vtEmpty, vtEmpty, ADODB::adOpenStatic, ADODB::adLockReadOnly, ADODB::adCmdText);
// Move to the Last Row
Recordset->MoveLast();
_variant_t bookmark = Recordset->Bookmark;
// Recordcount
long tmp = Recordset->RecordCount;
Recordset->Close();
pConn->Close();
::CoUninitialize();
Is there a way to use the Recordset Property, without transferring all rows to the client??
I need help with the C++ mysqlpp driver calling a stored procedure and retrieving its output parameter. The queries seem to pass successfully but trying to get the stored value causes segmentation fault. My current pseudo code is:
mysqlpp::Connection* connection; // the connection type I am bound to use, no createStatement, prepareStatement methods
Query query = connection->query();
Query transactionQuery = connection->query();
query << "CALL sp_get_transactions_count(" << inputId << ", #transactionsCount);";
transactionQuery << "SELECT #transactionsCount as combinations;";
ClearQuerySentry cleanUpQuery(transactionQuery);
query.exec();
mysqlpp::StoreQueryResult transactionsResult = transactionQuery.store();
if (!transactionsResult || transactionsResult.num_rows() == 0)
{
logWarning(....);
}
else
{
const mysqlpp::Row& transactionRecord = result[0];
environment.pairTransactionsCount = verboseLexicalCast<int>(transactionRecord, "combinations"); // segfault on trying to cast static_cast<const char*>(row[fieldName.c_str()]))
}
I am not very experienced with mysqlpp and MySQL as a whole so it is possible my perception of the solution to be wrong. Thanks in advance.
I want to get access to a sub object of a COM object. In my example I use the CANoe COM Server.
In my program I create a CAN interface to the CANoe Application. Here is an extract of my code so far and it does exactly what I want:
HRESULT result;
//prepare for COM handling...
result = CoInitialize(NULL);
//get CLSID of CANoe...
result = CLSIDFromProgID(L"CANoe.Application", &clsid);
if(SUCCEEDED(result))
{
//connect to COM interface of CANoe...
result = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, IID_IApplication, (void**) &pIApp);
if(SUCCEEDED(result))
{
qDebug() << "COM connection established";
}
else
{
qDebug() << "COM connection error";
}
}
else
{
qDebug() << "Error: CLSID";
}
Now I want to get access to a sub object of the COM Server. For example the Measurement object. I tried it with the method pIApp->get_UI()
IDispatch* pIDis;
IMeasurement* pIMeasurement;
result = pIApp->get_UI(&pIDis);
pIMeasurement = (IMeasurement*) pIDis;
The pointer to the COM object needs to be a pointer of the type IMeasurement, so I can use all the methods defined in the header file. But the method get_UI only supports pointer of the type IDispatch. I tried to cast the pointer from type IDispatch to IMeasurement. But the program crashs at runtime.
I also tried to create a new interface directly to the sub object:
result = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, IID_IMeasurement, (void**) &pIMeasurement);
But in this try in the variable result there is saved an error and I can't access the methods of the sub object Measurement.
Where is my mistake and how can I get access to the sub object?
Thank you for all answers and hints!
Thanks to #WhozCraig, #Hans Passant and #Eric Brown for the hints in the comments.
I was able to solve my problem with the following code:
IDispatch* pIDispatch;
//get pointer pIDispatch to Measurement object of CANoe...
result = pIApp->get_Measurement(&pIDispatch);
if(SUCCEEDED(result))
{
//pointer pIDispatch to pIMeasurement...
result = pIDispatch->QueryInterface(IID_IMeasurement, (void**) &pIMeasurement);
if(SUCCEEDED(result))
{
pIDispatch->Release();
//work with connection here...
pIMeasurement->Release();
}
}
In my project ,i want to monitor sofeware installation and unstallation in my system, so i use WMI event mechanism,but now i encounter a problem and have a question.
problem:
i want to monitor HKLM'SOFTWARE\Microsoft\Windows\currentversion\unistall',but code[1] works error(ExecNotificationQueryAnsync failed with =0x80041058).while code[2] works ok,what's wrong?
[1]
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software\\Microsoft\\Windows\\currentversion\\unistall'"
),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
[2]
hres = pSvc->ExecNotificationQueryAsync(
_bstr_t("WQL"),
_bstr_t("SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software'"
),
WBEM_FLAG_SEND_STATUS,
NULL,
pStubSink);
question:in My event consumer ,i want to get the software's name ,how can i do ?
thanks!!
Just use
SELECT * FROM RegistryTreeChangeEvent WITHIN 1 " "WHERE Hive='HKEY_LOCAL_MACHINE'" "AND RootPath='software\\\\Microsoft\\\\Windows\\\\currentversion\\\\unistall'"