Hmm so after a long time I’m back with a new post.
This time I came across a cool API called NtQueryObject. One purpose of the API is to find the name of object type it’s given. For example if you are passing a process handle this API will return “Process” as the string. The caveat of using this API is that it can be changed in the future. So be very careful with the signature of the function, cross check with the documentation before using. Use it at your own risk.
So let’s see the code, since API doesn’t have a lib associated with it we’ll have to use GetProcAddress to retrieve function address. The function signature of NtQueryObject looks like…
NTSTATUS NtQueryObject(__in_opt HANDLE Handle, __in OBJECT_INFORMATION_CLASS ObjectInformationClass, __out_opt PVOID ObjectInformation, __in ULONG ObjectInformationLength, __out_opt PULONG ReturnLength );
The second parameter to the API can be of two types. The one type of interest for this case is PUBLIC_OBJECT_TYPE_INFORMATION. If we pass this type as second parameter then the API is expecting a PUBLIC_OBJECT_TYPE_INFORMATION as third parameter. The contents of the structure is as follows…
typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
UNICODE_STRING TypeName;
ULONG Reserved [22]; // reserved for internal use
} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
The first member in the structure is the one that returns the string, only issue we’ll have to allocate this in special manner. Please have a look in the below function to see how I’ve allocated memory for this structure.
void GetHandleTypeName(HANDLE hHandle, CString& TypeName)
{
typedef NTSTATUS (NTAPI *NtQueryObjectPtr)(HANDLE Handle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength);
HMODULE hMod = LoadLibrary(_T("NtDll.dll"));
NtQueryObjectPtr QueryObj = (NtQueryObjectPtr)::GetProcAddress(hMod, "NtQueryObject");
ASSERT(QueryObj);
ULONG OutSize = 0;
NTSTATUS NtStatus = QueryObj(hHandle, ObjectTypeInformation, NULL, 0, &OutSize);
PPUBLIC_OBJECT_TYPE_INFORMATION TypeInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)calloc(1, OutSize);
ULONG InSize = OutSize;
NtStatus = QueryObj(hHandle, ObjectTypeInformation, TypeInfo, InSize, &OutSize);
TypeName = TypeInfo->TypeName.Buffer;
free(TypeInfo);
}
// This is how we invoke the function note: GetCurrentProcess() call. CString cs; GetHandleTypeName(GetCurrentProcess(), cs); MessageBox(cs);
If you are creating a dialog with style WS_CHILD then make sure you also have DS_CONTROL and DS_CONTROLPARENT enabled for the dialog.
The reason being that the dialog at a time is a control (embedded inside another window) and a control parent (housing other controls). If these styles are not specified calls to GetWindowRect and then a subsequent ScreenToClient will return top co-ordinates in negative leading to some confusion.
It’s quite handy to show the standard windows open with dialog, which lists all installed applications along with a browse button. In Windows XP there is no straight forward way of doing this.
In Windows Vista onwards Microsoft has provided a shell API for this purpose. It’s called SHOpenWithDialog.
Some sample code (couldn’t test this though since I’m on XP at home)…
OPENASINFO Info = { 0 };
Info.oaifInFlags = OAIF_EXEC | OAIF_ALLOW_REGISTRATION;
SHOpenWithDialog(NULL, &Info);
A screenshot of the dialog in XP…
Recently a user asked this question in MSDN forums. He had MBCS enabled for his application and also wanted to enable unicode characters in a particular edit control. Note MFC only create unicode controls if UNICODE is defined in project settings.
So in order to explicitly create controls that support UNICODE characters we use the ‘W’ functions. For example: for our user he should use “CreateWindowW” function. Note the last ‘W’ in the function. ANSI windows are created by calling “CreateWindowA” function (this also means that we can explicitly create a non-unicode control).
Also make sure you use only UNICODE API’s for a control created in this manner. For e.g. always call GetWindowTextW instead of GetWindowTextA. Never use MFC on such a control if it’s not created by MFC framework, I mean don’t call CWnd::Attach on this control. Mainly because MFC is operating in non-unicode environment but our control is a UNICODE one.
Now once such a control is created you can paste characters of different languages, for e.g. Chinese, Japanese, etc even though the application is not a UNICODE supporting one.
The main reason for posting this issue is to help MFC/Win32 beginners. But anyway it’s a good read
, so once upon a time…
If you’re a beginner with window’s ComboBox controls then you might end up with a bald head thinking and thinking about a weird behavior of combo’s after it’s creation. The combo as such is a great control but there are certain important things to keep in mind while creating a combo.
So what are the problems? Well make it singular, “Problem”. One and the only problem with this control is shown in this screenshot…
I’ve clicked the drop down arrow but cannot see the dropdown. This one is created via resource editor. The problem here is, just adding a combo is not enough but we’ve also got to set the size of the drop down via resource editor. So follow these steps, as shown in the screen shot to fix this issue…
So that’s it. The white drag rectangle denotes combo drop down size. Press Ctrl + T to test this. Please note that this is not a bug but a feature of resource editor since there isn’t an another way to set drop down size for a combo via resource editor. But I agree that they should’ve set a better default drop down size instead of a zero height drop down.
Now this was via resource editor. It’s bit different when creating dynamically via code using CComboBox::Create function. Note that you have to give a valid height value. This height value will be the dropdown size for this combo.
See this e.g.
m_Combo.Create( WS_VISIBLE | WS_TABSTOP | WS_BORDER | CBS_DROPDOWNLIST | CBS_SORT,
CRect( 10, 10, 200, 300 ),
this,
IDC_COMBO1 + 1 );
m_Combo.SetFont( GetFont(), TRUE );
Hope you’ve noticed the last big value given to Combo via CRect, 300. That’s the drop down height. Normally beginners set it to 30 or 40 which results in this issue.
See the resultant screenshot…
Not a big deal for experts but for beginners, well I’ve been a beginner too, it’s one painful issue.
So what does SendInput API do?
SendInput API is a helper function to simulate keyboard and mouse inputs. It’s an ideal function to insert characters into a password which otherwise is not possible. Here is what MSDN says about this function…
“The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse) or by calls to keybd_event, mouse_event, or other calls to SendInput.”
Here is a simple and basic function which sends a given text to a foreground window (my earlier function was crap so I replaced it with this new one that works for all texts, haven’t tried out with foreign keyboards though)…
BOOL SendText( LPCSTR lpctszText )
{
vector< INPUT > EventQueue;
char Buff[120] = {0};
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, Buff, sizeof(Buff));
HKL hKeyboardLayout = ::LoadKeyboardLayout( Buff, KLF_ACTIVATE );
const int Len = strlen( lpctszText );
for( int Index = 0; Index &amp;amp;amp;lt; Len; ++Index )
{
INPUT Event = { 0 };
const SHORT Vk = VkKeyScanEx(lpctszText[Index], hKeyboardLayout);
const UINT VKey = ::MapVirtualKey( LOBYTE( Vk ), 0 );
if( HIBYTE( Vk ) == 1 ) // Check if shift key needs to be pressed for this key
{
// Press shift key
::ZeroMemory( &amp;amp;amp;amp;Event, sizeof( Event ));
Event.type = INPUT_KEYBOARD;
Event.ki.dwFlags = KEYEVENTF_SCANCODE;
Event.ki.wScan = ::MapVirtualKey( VK_LSHIFT, 0 );
EventQueue.push_back( Event );
}
// Keydown
::ZeroMemory( &amp;amp;amp;amp;Event, sizeof( Event ));
Event.type = INPUT_KEYBOARD;
Event.ki.dwFlags = KEYEVENTF_SCANCODE;
Event.ki.wScan = VKey;
EventQueue.push_back( Event );
// Keyup
::ZeroMemory( &amp;amp;amp;amp;Event, sizeof( Event ));
Event.type = INPUT_KEYBOARD;
Event.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
Event.ki.wScan = VKey;
EventQueue.push_back( Event );
if( HIBYTE( Vk ) == 1 )// Release if previouly pressed
{
// Release shift key
::ZeroMemory( &amp;amp;amp;amp;Event, sizeof( Event ));
Event.type = INPUT_KEYBOARD;
Event.ki.dwFlags = KEYEVENTF_SCANCODE| KEYEVENTF_KEYUP;
Event.ki.wScan = ::MapVirtualKey( VK_LSHIFT, 0 );
EventQueue.push_back( Event );
}
}// End for
if( hKeyboardLayout )
{
UnloadKeyboardLayout( hKeyboardLayout );
}
return ::SendInput( EventQueue.size(), &amp;amp;amp;amp;EventQueue[0], sizeof( INPUT ));
}
Use function PathIsDirectoryEmpty. Some working facts about this API…
- Returns false if directory does not exist
- Returns true is directory is empty
- Return false if directory contains nested directories but no files
- Returns false if there are files in directory
- Returns false if given path points to a directory
- C:\ is considered a directory
- Does not auto expand environment variables in given path
- Ok with spaces in path
Usage…
CString Directory = _T( "C:\\Nibu babu thomas" ); // This directory exists const BOOL Empty = PathIsDirectoryEmpty( Directory ); // Call returns true ASSERT( Empty );





