Saturday, December 20, 2008

Function to get the local system Administrator Name

A codeproject poster asked this question. He was already aware of the NetLocalGroupGetMembers function with which, was can the list of users in any groups in the system. How were he wasn't quite sure how to use it and there wasn't any sample code in the internet. So I wrote a sample and posted in codeproject and here is the copy of it.
LPLOCALGROUP_MEMBERS_INFO_1  pstMembersInfo = 0;
DWORD entriesread = 0;
DWORD totalentries = 0;
if( 0 != NetLocalGroupGetMembers( NULL, _T("Administrators"), 1, (LPBYTE*)
&pstMembersInfo,MAX_PREFERRED_LENGTH,
&entriesread, &totalentries, 0 ))
{
AfxMessageBox( _T("NetLocalGroupGetMembers failed !"));
return ;
}
for( DWORD dwIdx =0; dwIdx < entriesread; dwIdx ++ )
{
AfxMessageBox( pstMembersInfo[dwIdx].lgrmi1_name );
}
NetApiBufferFree( pstMembersInfo );

Monday, October 27, 2008

How to find whether the parent process is GUI or Console

This is not 100% fool proof. How ever in normal cases, this works great. This technique can be used to find out, whether the child application was launched from a GUI application or from a Console application.

if( AttachConsole( ATTACH_PARENT_PROCESS ))
{
AfxMessageBox( _T("Parent process is a console application"));
}
else
{
AfxMessageBox( _T("Parent process is not a console application"));
}

Tuesday, August 26, 2008

new with empty bracket

Have you ever wrote a statement like..

int *pnValue = new int[];

One of my friend asked me what will happen if the above statement is executed. Executed ??? I though the code won't even compile. Surprisingly it compile and even returned a pointer. Wow that was some thing unbelievable.

OK now the question is, what will be size of memory that pnValue points?

The two API's in windows that allocates and de allocates the memeory are HeapAlloc and HeepFree. The CRT functions malloc and free are actually wrappers the above API. The new, new[], delete, delete[] are again another wrapper around the malloc and free. So when ever you allocates some memory using new or new[], it will finally reach the HeapAlloc function. This function is defined as

LPVOID WINAPI HeapAlloc(
__in HANDLE hHeap,
__in DWORD dwFlags,
__in SIZE_T dwBytes
);


From the above definition, you can see that the third parameter to this function is the number of BYTES to be allocated . So to find out what "new int[]" returns, we can put a break point in the entry point of HeapAlloc and check the value of dwBytes( in dis assembly ).

when I tried, the dwBytes turned out be 1 !!! This one byte cannot even hold one int variable. That means any further operation using such a pointer will possibly crash.

Another interesting thing is "int *pnValue = new int[0];" also returns a pointer pointing a memory of 1 byte long.

Wednesday, August 20, 2008

How to open Popup Blocker Settings window of IE programmatically

How to open Popup Blocker Settings window of IE programmatically??

Well it is with the help of "DisplayPopupWindowManagementDialog" function in the "C:\WINDOWS\system32\inetcpl.cpl".

But here rather just showing a misterious function, I would like to explain the methods by which I found out the name of function.

This question was asked by some one in the codeproject and at that time I was also unaware of any function for this. How ever I felt it interesting so just decided to have a try.

At first I took this "Popup Blocker Settings " dialog in the IE. My first intention was to find out the dll name which created the dialog. There is an application called WinID[^] with which we can find which dll created a perticular windows. In one of my previous post, I have explained How to find which dll / exe created a window.[^] using code. Below is a screenshot of what WinID showed me for the "Popup Blocker Settings" dialog .



It told me that "USER32.dll" has created the dialog. Liar... I was much sure that user32.dll isn't the real dll behind it. So this technique to find the dll didn't really work. So I had to find another way...

Every window has a thread associated with it. If you have the window handle, you can easily retirive the thread Id associated with it using the GetWindowThreadProcessId function. Any way I am not going to code for this. Tools like spy++, WinID displays the thread id of the window if we select a window using it. So the Thread ID displayed in Spy++ was 0xB94( 2964 in decimal ).

If we took the properties of a process in the process explorer, it will list all the threads in the process and each thread's call stack. So the thing next to do is to select the iexplorer process, select the thread with ID 2964 and took its call stack.



And in the call stack, there was only one un familiar dll and function the "inetcpl.cpl" and the DisplayPopupWindowManagementDialog function in it. So I found out the "inetcpl.cpl" file in the system32 folder and when double clicked on it, huiii it shows the "internet options" dialog.

The control panel files (.cpl ), are just a dll with a some special export functions( If you want to know more about control panel files I suggest you to read Paul DiLascia's Q&A[^] article ). With the dependency walker, I confirmed the presence of DisplayPopupWindowManagementDialog in it. But to call this function, I need to the find how it is declared, what all are the arguments etc. Fortunately some else has already document the function proto and with a google search, I was able to find it out. Happy ending!!!!

And ho ya here is the sample code..

typedef BOOL (WINAPI *DisplayPopupWindowP)( HANDLE hWnd, LPCTSTR lpCaption );
void CDialogBasedDlg::OnBnClickedButton1()
{
HMODULE hModule = LoadLibrary( _T("inetcpl.cpl") );
DisplayPopupWindowP DisplayPopupWindowManagementDialog =
( DisplayPopupWindowP)GetProcAddress(hModule,
"DisplayPopupWindowManagementDialog" );
if( !DisplayPopupWindowManagementDialog )
{
return;//error
}
DisplayPopupWindowManagementDialog( m_hWnd,
_T("www.Sitetounblock.com"));
}

Sunday, August 17, 2008

GetFinalPathNameByHandle API Hungs

GetFinalPathNameByHandle is an new API introduced in windows vista. As you can read from MSDN, the purpose of this API is to return the file name corresponding to a file handle .

Some months back, I have written a small utility OpenedFileFinder which list all the file that are opened under a certain folder. While writing this application,the main problem I came across was to get the file name from the handle. Initially I used a function called NtQueryObject(). But the problem with this API is that if we try to query the details for certain object such as pipes, directory handles etc, it will hangs. So in my application finally I have to introduce a driver to get round of this hanging problem. When I found the new GetFinalPathNameByHandle(), I was so happy and I thought at least I can avoid the driver in the vista. So I had a try on this API. But I came to find that this API also have the same hanging problem which I described earlier.

It seems the GetFinalPathNameByHandle is also using the same NtQueryObject() to get the file name and so it hangs. Any how, I have reported this bug to the microsoft connect. Let us see how they solve the problem.

Another API, that worth mentioning here is GetFileInformationByHandleEx(), which is also a new API introduced in Vista. Using this API also, I can get the file name from a handle. So I decided to check whether the same problem exists in this API also. Surprisingly it worked fine. And in MSDN also it is mentioned that it uses a driver for attaining the task. So I highly suggest every one to use GetFileInformationByHandleEx() API instead of GetFinalPathNameByHandle().

Thursday, June 19, 2008

How Local Static Variable Is Implemented in vc++

As every one knows, static variables are initialized only ones, even though it is declared in a function. In this post, I will explain how the compiler implements this.

OK let start with the storage of the static variables. Where do you think a static variable declared inside a function is stored? If your answer is on the stack, you are wrong. All static and global variables are stored in a section called ".data" in the exe. For example check the below code.
int g_GlobalVariable = 0x10;
static int nValue1 = 0x11;
void main()
{
static int nValue2 = 0x12;
// Take the address

int *pglobal = &g_GlobalVariable;
int *pValue1 = &nValue1;
int *pValue2 = &nValue2;
}
When executed, the values of pglobal, pValue1 and pValue2 were 0x408020, 0x408024 and 0x408028 respectively. Which means, all the three variables were stored in three consecutive locations. In the PE view we can see these variables stored in the ".data" section.





You can see that the "nValue2" variable is initialized at the compile time itself. so no instruction is generated by the compiler for a statement like static int nValue2 = 0x12;

So compiler did a nice job by setting the value to variable at the compile time itself. But that was a C type object. What if we declare a static C++ object inside a function. This time the compiler cannot initialize the variable at the compile time because the constructor need to be invoked to initialize a C++ object. Consider the below code

class TestClass
{
public:
TestClass()
{
m_nMemeberVar = 10;
}
int m_nMemeberVar;
};
TestClass& AFunction()
{
static TestClass cppObject;
return cppObject;
}

In the above code, the AFunction() function creates a static object of class TestClass and as you know the cppObject will be initialized only once. How does the compiler manages to do it? Well answer is compiler keeps a flag!!! I.e when the compiler sees a c++, static object is declared inside a function, it will create a global byte variable with value 0 and some addition instruction such that the constructor of the object will be called only if the value of the byte variable is 0 and it also set the value of the byte variable as 1. So from the next time onwards, the constructor will not be called. Below is the dis assembly for the statement static TestClass cppObject.

static TestClass cppObject;
// Zero out the eax register
00401E79 xor eax,eax
// Copy the flag variable to al register
00401E7B mov al,[`AFunction'::`2'::$S230 (00408104)]
00401E80 and eax,1
// Check eax equal to zero
00401E83 test eax,eax
// If it is not zero, go to end.
00401E85 jne AFunction+3Dh (00401ead)
// Copy the flag variable to the cl register
00401E87 mov cl,byte ptr [`AFunction'::`2'::$S230 (00408104)]
// cl = 1
00401E8D or cl,1
// Copy back the content of cl register to the flag variable
00401E90 mov byte ptr [`AFunction'::`2'::$S230 (00408104)],cl
// Call the constructor of cppObject
00401E96 mov ecx,offset theApp+0C8h (00408100)
00401E9B call TestClass::TestClass (00401ec0)

Monday, May 5, 2008

Optimizing Storage for Constant Data

In programs we usually declare constant string data. Like..

const char* g_pchar = "this is a string";

You might be knowing that if we run multiple copies of a exe or dll, the code portion is not duplicated per process. So do the constant data. This is because the constant datas are stored in a special section of exe called ".rdata"( The code protion is stored in the ".text" section ). But guess what will happen if we have declaration like..

const CString g_str("this is the worst thing I can do");

Now you've got the CString object (which is quite small) in the .bss section( .bss section stores nonconstant uninitialized data ), and you've also got a character array in the .data section( Nonconstant initialized data ), neither of which can be backed by the EXE file. To make matters worse, when the program starts, the CString class must allocate heap memory for a copy of the characters. You would be much better off using a const character array instead of a CString object. So never ever declare like that ( Reference "Programming Microsoft vc++" by David Kruglinski ).

OK that was the theory. Now the reason why I stated the above theory is that, last week, I installed the latest VS 2008 feature pack. This feature pack had some new classes for MFC. So I decided to check out the new classes. The CWinAppEx is on among them. On the very first function I stepped in( constructor of the CWinAppEx ), I found the following piece of code..

const CString strRegEntryNameWorkspace = _T("Workspace");
m_strRegSection = strRegEntryNameWorkspace;

ops . And when I scrolled up, there was another bunch of similar codes

static const CString strRegEntryNameControlBars = _T("\\ControlBars");
static const CString strWindowPlacementRegSection = _T("WindowPlacement");
static const CString strRectMainKey = _T("MainWindowRect");
static const CString strFlagsKey = _T("Flags");
static const CString strShowCmdKey = _T("ShowCmd");
static const CString strRegEntryNameSizingBars = _T("\\SizingBars");
static const CString strRegEntryVersion = _T("ControlBarVersion");
static const CString strVersionMajorKey = _T("Major");
static const CString strVersionMinorKey = _T("Minor");


I dont think any one has seen such a badly written, poor quality code in the old MFC 4 code. Never did I. If MFC starts like this, where will the developers using MFC ends?

When I discussed about this in code project and MSDN forum, I got some interesting response. That's how I came to here about Wirth's law[^] , which states

Software gets slower, faster than hardware gets faster.
or
Software is decelerating faster than hardware is accelerating.

Very true and you just saw one example.

Monday, April 21, 2008

Loader snaps

In one of my previous post, I mentioned about breaking the executing on dll Load. This post is actually a continutation of that one.

Normally if we start an application from the debugger in the debugging mode, the output window shows some messages as shown below.

Loaded 'c:\WINDOWS\system32\calc.exe', no matching symbolic information found.
Loaded 'ntdll.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\kernel32.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\shell32.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\advapi32.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\rpcrt4.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\secur32.dll', no matching symbolic information found.
Actually it is debugger who shows this messages. But if want, you can ask for more information and traces of the loading process, to the loader. I.e, there is flag in the registry, which specifies the Loader to show more information about the loading process. To show those snaps, you have to added a DWORD value with name "GlobalFlag" under the
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager", set its value to 2 and then restart machine.

Below is the loader snaps of calc.exe after setting the flag.

Loaded 'c:\WINDOWS\system32\calc.exe', no matching symbolic information found. Loaded 'ntdll.dll', no matching symbolic information found.
Loaded 'C:\WINDOWS\system32\kernel32.dll', no matching symbolic information found.
LDR: LdrLoadDll, loading ShimEng.dll from
LDR: Loading (DYNAMIC, NON_REDIRECTED) c:\WINDOWS\system32\ShimEng.dll
Loaded 'C:\WINDOWS\system32\shimeng.dll', no matching symbolic information found.
LDR: ShimEng.dll bound to ntdll.dll
LDR: ShimEng.dll has correct binding to ntdll.dll
LDR: ShimEng.dll bound to KERNEL32.dll
LDR: ShimEng.dll has stale binding to KERNEL32.dll
LDR: Stale Bind KERNEL32.dll from ShimEng.dll
LDR: LdrGetProcedureAddress by NAME - SE_InstallBeforeInit
LDR: LdrGetProcedureAddress by NAME - SE_InstallAfterInit
LDR: LdrGetProcedureAddress by NAME - SE_DllLoaded
LDR: LdrGetProcedureAddress by NAME - SE_DllUnloaded
LDR: LdrGetProcedureAddress by NAME - SE_GetProcAddress
LDR: LdrGetProcedureAddress by NAME - SE_ProcessDying
LDR: LdrGetDllHandle, searching for ShimEng.dll from
LDR: LdrGetDllHandle, searching for C:\WINDOWS\AppPatch\AcGenral.DLL from
LDR: LdrLoadDll, loading C:\WINDOWS\AppPatch\AcGenral.DLL from
LDR: Loading (DYNAMIC, NON_REDIRECTED) C:\WINDOWS\AppPatch\AcGenral.DLL
Loaded 'C:\WINDOWS\AppPatch\AcGenral.dll', no matching symbolic information found.
LDR: AcGenral.DLL bound to ntdll.dll
LDR: AcGenral.DLL has correct binding to ntdll.dll
LDR: AcGenral.DLL bound to KERNEL32.dll
LDR: AcGenral.DLL has stale binding to KERNEL32.dll
LDR: AcGenral.DLL bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: AcGenral.DLL has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from AcGenral.DLL
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlSizeHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlReAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: AcGenral.DLL bound to USER32.dll
LDR: AcGenral.DLL has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to GDI32.dll
LDR: AcGenral.DLL has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to ADVAPI32.dll
LDR: AcGenral.DLL has correct binding to ADVAPI32.dll
LDR: AcGenral.DLL bound to WINMM.dll
LDR: Loading (STATIC, NON_REDIRECTED) c:\WINDOWS\system32\WINMM.dll
Loaded 'C:\WINDOWS\system32\winmm.dll', no matching symbolic information found.
LDR: WINMM.dll bound to ntdll.dll
LDR: WINMM.dll has correct binding to ntdll.dll
LDR: WINMM.dll bound to USER32.dll
LDR: WINMM.dll has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from WINMM.dll
LDR: WINMM.dll bound to GDI32.dll
LDR: WINMM.dll has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from WINMM.dll
LDR: WINMM.dll bound to KERNEL32.dll
LDR: WINMM.dll has stale binding to KERNEL32.dll
LDR: WINMM.dll bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: WINMM.dll has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from WINMM.dll
LDR: LdrGetProcedureAddress by NAME - RtlReAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlSizeHeap
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: WINMM.dll bound to ADVAPI32.dll
LDR: WINMM.dll has correct binding to ADVAPI32.dll
LDR: WINMM.dll bound to RPCRT4.dll
LDR: WINMM.dll has stale binding to RPCRT4.dll
LDR: Stale Bind RPCRT4.dll from WINMM.dll
LDR: AcGenral.DLL has correct binding to WINMM.dll
LDR: AcGenral.DLL bound to ole32.dll
Loaded 'C:\WINDOWS\system32\ole32.dll', no matching symbolic information found.
LDR: ADVAPI32.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from ADVAPI32.dll
LDR: GDI32.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from GDI32.dll
LDR: KERNEL32.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from KERNEL32.dll
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: LdrGetProcedureAddress by NAME - RtlSizeHeap
LDR: LdrGetProcedureAddress by NAME - RtlReAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: msvcrt.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from msvcrt.dll
LDR: ntdll.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from ntdll.dll
LDR: RPCRT4.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from RPCRT4.dll
LDR: USER32.dll used by ole32.dll
LDR: Snapping imports for ole32.dll from USER32.dll
LDR: AcGenral.DLL has stale binding to ole32.dll
LDR: Stale Bind ole32.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to OLEAUT32.dll
Loaded 'C:\WINDOWS\system32\oleaut32.dll', no matching symbolic information found.
LDR: ADVAPI32.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from ADVAPI32.dll
LDR: GDI32.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from GDI32.dll
LDR: KERNEL32.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from KERNEL32.dll
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: msvcrt.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from msvcrt.dll
LDR: ole32.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from ole32.dll
LDR: RPCRT4.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from RPCRT4.dll
LDR: USER32.dll used by OLEAUT32.dll
LDR: Snapping imports for OLEAUT32.dll from USER32.dll
LDR: AcGenral.DLL has stale binding to OLEAUT32.dll
LDR: Stale Bind OLEAUT32.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to MSACM32.dll
LDR: Loading (STATIC, NON_REDIRECTED) c:\WINDOWS\system32\MSACM32.dll
Loaded 'C:\WINDOWS\system32\msacm32.dll', no matching symbolic information found.
LDR: MSACM32.dll bound to msvcrt.dll
LDR: MSACM32.dll has stale binding to msvcrt.dll
LDR: Stale Bind msvcrt.dll from MSACM32.dll
LDR: MSACM32.dll bound to ntdll.dll
LDR: MSACM32.dll has correct binding to ntdll.dll
LDR: MSACM32.dll bound to USER32.dll
LDR: MSACM32.dll has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from MSACM32.dll
LDR: MSACM32.dll bound to GDI32.dll
LDR: MSACM32.dll has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from MSACM32.dll
LDR: MSACM32.dll bound to KERNEL32.dll
LDR: MSACM32.dll has stale binding to KERNEL32.dll
LDR: MSACM32.dll bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: MSACM32.dll has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from MSACM32.dll
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: MSACM32.dll bound to ADVAPI32.dll
LDR: MSACM32.dll has correct binding to ADVAPI32.dll
LDR: MSACM32.dll bound to WINMM.dll
LDR: MSACM32.dll has correct binding to WINMM.dll
LDR: AcGenral.DLL has correct binding to MSACM32.dll
LDR: AcGenral.DLL bound to VERSION.dll
Loaded 'C:\WINDOWS\system32\version.dll', no matching symbolic information found.
LDR: VERSION.dll bound to KERNEL32.dll
LDR: VERSION.dll has stale binding to KERNEL32.dll
LDR: VERSION.dll bound to NTDLL.DLL via forwarder(s) from kernel32.dll
LDR: VERSION.dll has correct binding to NTDLL.DLL
LDR: Stale Bind KERNEL32.dll from VERSION.dll
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: VERSION.dll bound to NTDLL.DLL
LDR: VERSION.dll has correct binding to NTDLL.DLL
LDR: AcGenral.DLL has correct binding to VERSION.dll
LDR: AcGenral.DLL bound to SHELL32.dll
LDR: AcGenral.DLL has stale binding to SHELL32.dll
LDR: Stale Bind SHELL32.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to SHLWAPI.dll
LDR: AcGenral.DLL has stale binding to SHLWAPI.dll
LDR: Stale Bind SHLWAPI.dll from AcGenral.DLL
LDR: AcGenral.DLL bound to USERENV.dll
Loaded 'C:\WINDOWS\system32\userenv.dll', no matching symbolic information found.
LDR: USERENV.dll bound to msvcrt.dll
LDR: USERENV.dll has stale binding to msvcrt.dll
LDR: Stale Bind msvcrt.dll from USERENV.dll
LDR: USERENV.dll bound to ntdll.dll
LDR: USERENV.dll has correct binding to ntdll.dll
LDR: USERENV.dll bound to ADVAPI32.dll
LDR: USERENV.dll has correct binding to ADVAPI32.dll
LDR: USERENV.dll bound to KERNEL32.dll
LDR: USERENV.dll has stale binding to KERNEL32.dll
LDR: USERENV.dll bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: USERENV.dll has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from USERENV.dll
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: USERENV.dll bound to RPCRT4.dll
LDR: USERENV.dll has stale binding to RPCRT4.dll
LDR: Stale Bind RPCRT4.dll from USERENV.dll
LDR: USERENV.dll bound to USER32.dll
LDR: USERENV.dll has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from USERENV.dll
LDR: AcGenral.DLL has correct binding to USERENV.dll
LDR: AcGenral.DLL bound to UxTheme.dll
LDR: Loading (STATIC, NON_REDIRECTED) c:\WINDOWS\system32\UxTheme.dll
Loaded 'C:\WINDOWS\system32\uxtheme.dll', no matching symbolic information found.
LDR: UxTheme.dll bound to msvcrt.dll
LDR: UxTheme.dll has stale binding to msvcrt.dll
LDR: Stale Bind msvcrt.dll from UxTheme.dll
LDR: UxTheme.dll bound to ntdll.dll
LDR: UxTheme.dll has correct binding to ntdll.dll
LDR: UxTheme.dll bound to KERNEL32.dll
LDR: UxTheme.dll has stale binding to KERNEL32.dll
LDR: UxTheme.dll bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: UxTheme.dll has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from UxTheme.dll
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlDeleteCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: UxTheme.dll bound to USER32.dll
LDR: UxTheme.dll has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from UxTheme.dll
LDR: UxTheme.dll bound to GDI32.dll
LDR: UxTheme.dll has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from UxTheme.dll
LDR: UxTheme.dll bound to ADVAPI32.dll
LDR: UxTheme.dll has correct binding to ADVAPI32.dll
LDR: AcGenral.DLL has correct binding to UxTheme.dll
LDR: Refcount WINMM.dll (1)
LDR: Refcount ole32.dll (1)
LDR: Refcount OLEAUT32.dll (1)
LDR: Refcount ole32.dll (2)
LDR: Refcount MSACM32.dll (1)
LDR: Refcount WINMM.dll (2)
LDR: Refcount VERSION.dll (1)
LDR: Refcount USERENV.dll (1)
LDR: Refcount UxTheme.dll (1)
[1cb0,1cac] LDR: Real INIT LIST for process c:\WINDOWS\system32\calc.exe pid 7344 0x1cb0
[1cb0,1cac] C:\WINDOWS\AppPatch\AcGenral.DLL init routine 6F8A5E1A
[1cb0,1cac] LDR: AcGenral.DLL loaded - Calling init routine at 6F8A5E1A
LDR: LdrGetDllHandle, searching for kernel32.dll from
LDR: LdrGetProcedureAddress by NAME - InitializeCriticalSectionAndSpinCount
LDR: LdrGetProcedureAddress by NAME - GetHookAPIs
[1cb0,1cac] LDR: Real INIT LIST for process c:\WINDOWS\system32\calc.exe pid 7344 0x1cb0
[1cb0,1cac] C:\WINDOWS\system32\Secur32.dll init routine 77FE2131
[1cb0,1cac] C:\WINDOWS\system32\RPCRT4.dll init routine 77E7628F
[1cb0,1cac] C:\WINDOWS\system32\ADVAPI32.dll init routine 77DD70D4
[1cb0,1cac] C:\WINDOWS\system32\USER32.dll init routine 7E42E966
[1cb0,1cac] C:\WINDOWS\system32\GDI32.dll init routine 77F16587
[1cb0,1cac] C:\WINDOWS\system32\msvcrt.dll init routine 77C1F2A1
[1cb0,1cac] C:\WINDOWS\system32\SHLWAPI.dll init routine 77F651FB
[1cb0,1cac] C:\WINDOWS\system32\SHELL32.dll init routine 7C9E7376
[1cb0,1cac] c:\WINDOWS\system32\WINMM.dll init routine 76B42B69
[1cb0,1cac] C:\WINDOWS\system32\ole32.dll init routine 774FD0A1
[1cb0,1cac] C:\WINDOWS\system32\OLEAUT32.dll init routine 77121558
[1cb0,1cac] c:\WINDOWS\system32\MSACM32.dll init routine 77BE1292
[1cb0,1cac] C:\WINDOWS\system32\VERSION.dll init routine 77C01135
[1cb0,1cac] C:\WINDOWS\system32\USERENV.dll init routine 769C15D4
[1cb0,1cac] c:\WINDOWS\system32\UxTheme.dll init routine 5AD71626
[1cb0,1cac] LDR: Secur32.dll loaded - Calling init routine at 77FE2131
[1cb0,1cac] LDR: RPCRT4.dll loaded - Calling init routine at 77E7628F
[1cb0,1cac] LDR: ADVAPI32.dll loaded - Calling init routine at 77DD70D4
[1cb0,1cac] LDR: USER32.dll loaded - Calling init routine at 7E42E966
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from c:\WINDOWS\system32;C:\WINDOWS\system32;C:\WINDOWS\system;C:\WINDOWS;
]LDR: LdrLoadDll, loading C:\WINDOWS\system32\IMM32.DLL from c:\WINDOWS\system32;C:\WINDOWS\system32;C:\WINDOWS\system;C:\WINDOWS;
]LDR: Loading (DYNAMIC, NON_REDIRECTED) C:\WINDOWS\system32\IMM32.DLL
Loaded 'C:\WINDOWS\system32\imm32.dll', no matching symbolic information found.
LDR: IMM32.DLL bound to USER32.dll
LDR: IMM32.DLL has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from IMM32.DLL
LDR: IMM32.DLL bound to ntdll.dll
LDR: IMM32.DLL has correct binding to ntdll.dll
LDR: IMM32.DLL bound to KERNEL32.dll
LDR: IMM32.DLL has stale binding to KERNEL32.dll
LDR: IMM32.DLL bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: IMM32.DLL has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from IMM32.DLL
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlSetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: IMM32.DLL bound to GDI32.dll
LDR: IMM32.DLL has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from IMM32.DLL
LDR: IMM32.DLL bound to ADVAPI32.dll
LDR: IMM32.DLL has correct binding to ADVAPI32.dll
[1cb0,1cac] LDR: Real INIT LIST for process c:\WINDOWS\system32\calc.exe pid 7344 0x1cb0
[1cb0,1cac] C:\WINDOWS\system32\IMM32.DLL init routine 763912C0
[1cb0,1cac] LDR: IMM32.DLL loaded - Calling init routine at 763912C0
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from c:\WINDOWS\system32;C:\WINDOWS\system32;C:\WINDOWS\system;C:\WINDOWS;
]LDR: LdrGetProcedureAddress by NAME - ImmWINNLSEnableIME
LDR: LdrGetProcedureAddress by NAME - ImmWINNLSGetEnableStatus
LDR: LdrGetProcedureAddress by NAME - ImmSendIMEMessageExW
LDR: LdrGetProcedureAddress by NAME - ImmSendIMEMessageExA
LDR: LdrGetProcedureAddress by NAME - ImmIMPGetIMEW
LDR: LdrGetProcedureAddress by NAME - ImmIMPGetIMEA
LDR: LdrGetProcedureAddress by NAME - ImmIMPQueryIMEW
LDR: LdrGetProcedureAddress by NAME - ImmIMPQueryIMEA
LDR: LdrGetProcedureAddress by NAME - ImmIMPSetIMEW
LDR: LdrGetProcedureAddress by NAME - ImmIMPSetIMEA
LDR: LdrGetProcedureAddress by NAME - ImmAssociateContext
LDR: LdrGetProcedureAddress by NAME - ImmEscapeA
LDR: LdrGetProcedureAddress by NAME - ImmEscapeW
LDR: LdrGetProcedureAddress by NAME - ImmGetCompositionStringA
LDR: LdrGetProcedureAddress by NAME - ImmGetCompositionStringW
LDR: LdrGetProcedureAddress by NAME - ImmGetCompositionWindow
LDR: LdrGetProcedureAddress by NAME - ImmGetContext
LDR: LdrGetProcedureAddress by NAME - ImmGetDefaultIMEWnd
LDR: LdrGetProcedureAddress by NAME - ImmIsIME
LDR: LdrGetProcedureAddress by NAME - ImmReleaseContext
LDR: LdrGetProcedureAddress by NAME - ImmRegisterClient
LDR: LdrGetProcedureAddress by NAME - ImmGetCompositionFontW
LDR: LdrGetProcedureAddress by NAME - ImmGetCompositionFontA
LDR: LdrGetProcedureAddress by NAME - ImmSetCompositionFontW
LDR: LdrGetProcedureAddress by NAME - ImmSetCompositionFontA
LDR: LdrGetProcedureAddress by NAME - ImmSetCompositionWindow
LDR: LdrGetProcedureAddress by NAME - ImmNotifyIME
LDR: LdrGetProcedureAddress by NAME - ImmLockIMC
LDR: LdrGetProcedureAddress by NAME - ImmUnlockIMC
LDR: LdrGetProcedureAddress by NAME - ImmLoadIME
LDR: LdrGetProcedureAddress by NAME - ImmSetOpenStatus
LDR: LdrGetProcedureAddress by NAME - ImmFreeLayout
LDR: LdrGetProcedureAddress by NAME - ImmActivateLayout
LDR: LdrGetProcedureAddress by NAME - ImmGetCandidateWindow
LDR: LdrGetProcedureAddress by NAME - ImmSetCandidateWindow
LDR: LdrGetProcedureAddress by NAME - ImmConfigureIMEW
LDR: LdrGetProcedureAddress by NAME - ImmGetConversionStatus
LDR: LdrGetProcedureAddress by NAME - ImmSetConversionStatus
LDR: LdrGetProcedureAddress by NAME - ImmSetStatusWindowPos
LDR: LdrGetProcedureAddress by NAME - ImmGetImeInfoEx
LDR: LdrGetProcedureAddress by NAME - ImmLockImeDpi
LDR: LdrGetProcedureAddress by NAME - ImmUnlockImeDpi
LDR: LdrGetProcedureAddress by NAME - ImmGetOpenStatus
LDR: LdrGetProcedureAddress by NAME - ImmSetActiveContext
LDR: LdrGetProcedureAddress by NAME - ImmTranslateMessage
LDR: LdrGetProcedureAddress by NAME - ImmLoadLayout
LDR: LdrGetProcedureAddress by NAME - ImmProcessKey
LDR: LdrGetProcedureAddress by NAME - ImmPutImeMenuItemsIntoMappedFile
LDR: LdrGetProcedureAddress by NAME - ImmGetProperty
LDR: LdrGetProcedureAddress by NAME - ImmSetCompositionStringA
LDR: LdrGetProcedureAddress by NAME - ImmSetCompositionStringW
LDR: LdrGetProcedureAddress by NAME - ImmEnumInputContext
LDR: LdrGetProcedureAddress by NAME - ImmSystemHandler
LDR: LdrGetProcedureAddress by NAME - CtfImmTIMActivate
LDR: LdrGetProcedureAddress by NAME - CtfImmRestoreToolbarWnd
LDR: LdrGetProcedureAddress by NAME - CtfImmHideToolbarWnd
LDR: LdrGetProcedureAddress by NAME - CtfImmDispatchDefImeMessage
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from
LDR: LdrGetDllHandle, searching for C:\WINDOWS\system32\IMM32.DLL from c:\WINDOWS\system32;C:\WINDOWS\system32;C:\WINDOWS\system;C:\WINDOWS;
]LDR: LdrLoadDll, loading LPK.DLL from c:\WINDOWS\system32;C:\WINDOWS\system32;C:\WINDOWS\system;C:\WINDOWS;
]LDR: Loading (DYNAMIC, NON_REDIRECTED) c:\WINDOWS\system32\LPK.DLL
Loaded 'C:\WINDOWS\system32\lpk.dll', no matching symbolic information found.
LDR: LPK.DLL bound to ntdll.dll
LDR: LPK.DLL has correct binding to ntdll.dll
LDR: LPK.DLL bound to KERNEL32.dll
LDR: LPK.DLL has stale binding to KERNEL32.dll
LDR: LPK.DLL bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: LPK.DLL has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from LPK.DLL
LDR: LdrGetProcedureAddress by NAME - RtlEnterCriticalSection
LDR: LdrGetProcedureAddress by NAME - RtlLeaveCriticalSection
LDR: LPK.DLL bound to GDI32.dll
LDR: LPK.DLL has stale binding to GDI32.dll
LDR: Stale Bind GDI32.dll from LPK.DLL
LDR: LPK.DLL bound to USER32.dll
NAME - GetThemeInt
LDR: LdrGetProcedureAddress by NAME - DrawThemeBackground
LDR: LdrGetProcedureAddress by NAME - IsThemeBackgroundPartiallyTransparent
LDR: LdrGetProcedureAddress by NAME - GetThemePartSize
LDR: LdrGetProcedureAddress by NAME - GetThemeBackgroundContentRect
LDR: LdrGetProcedureAddress by NAME - DrawThemeText
LDR: LdrGetProcedureAddress by NAME - DrawThemeParentBackground

Optionally we can set the flag under the "HLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" by adding a key in the name of the exe for which you want to show Loader information and then adding the "GlobalFlag" under it.( This is the easiest way because you needn't to restart your machine in this case. )

Here I mentioned only one value that can be set to the "GlobalFlag". To see the other possible values see GlobalFlags for Windows .

Thursday, April 17, 2008

Pointer pointing to Stack or Heap ??

Today on Code project some one posted a question like "Is there any way to find whether a pointer points to stack or heap". Is there actually an API for the same??

Well windows dosen't provide an API or a straight forward way to acomplish this. Any how we can find a pointer points to stack or heap by simple computations and ofcourse with the help of TIB( Thread Infomation Block - If you want to learn more about TIB, have a look to the Under The Hood article of Matt Pietrek ). In the Thread information block, there are two members, the "StackTop"( located at FS[4] ) and "StackBase" ( located at FS[8] ). The "StackTop" is the memory from which the stack started, and the "StackBase" is the stack location the program commits upto that point. So any object created on stack will have an address between this two pointers. So if we get a pointer just check whether the pointer falls between the above two memory locations. if it does, then it can be consider a pointer to some stack object. So here is my API to find whether the pointer points to stack or heap.

// This function will return true if the pointer points to stack. Other wise false
bool IsMemoryOnStack( LPVOID pVoid )
{
LPVOID dwStackTop = 0;
LPVOID dwStackLowCurrent = 0;
__asm
{
mov EAX, FS:[4]
mov dwStackTop, eax
mov EAX, FS:[8]
mov dwStackLowCurrent, eax
}
if( pVoid <= dwStackTop && pVoid >= dwStackLowCurrent )
{
// The memory lie between the stack top and stack commited.
return true;
}
// Pointer dosen't point to the stack
return false;
}

Sample code that uses the above API..

void main()
{
int OnStack;
bool bOnStack = IsMemoryOnStack( &OnStack );// Returns true
int *pOnHeap = new int;
bOnStack = IsMemoryOnStack( pOnHeap );// Returns false
}

Wednesday, April 16, 2008

Break application on dll Load

What will you do if you encounter a crash in an application before it reaches the entry point ok exe. I. e the crach happends before the control reaches the WinMain. In such cases the crash might have happened in the dll loaded by the exe. To be more specific say in the DllMain() of dlls. In most cases we will not be having the source code of all dll so that we can put some breakpoint in the DllMain() and debug. So how to track which dll is causing the problem...
The windows loader provids an option to break the debugee while loading dlls. For this we have to set appropriate values under "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" key.

Suppose I have a application which have dependency with "Foo.dll" and I want the bebugger to break just before loading "Foo.dll". To do so create a key under the "Image File Execution Options" like
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Foo.dll".
Add a DWORD value under this key with name "BreakOnDllLoad" and set its value as one.

Now if you start the application from the debugger. The debugeer will report a breakpoint hit during startup. This break point will be just above the call to Dll entry point of foo.dll.( The entry point is_DllMainCRTStartup if the dll is written using vc++. This function later calls DllMain())


Tuesday, April 15, 2008

__asm int 3 in template function ( in VC6 )

We usually use __asm int 3 in the code to hard code break points. But have you tried setting a __asm int 3 in a template function? Like...

template<class T> int Testfunc( T Obj )
{
__asm int 3;
return Obj++;
}

void main()
{
Testfunc( 1 );
};

The above code will never get compiled in vc6. It will generate the below error

"fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 1794)
Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more information
Generating Code...Command line warning D4028 : minimal rebuild failure, reverting to normal build
Error executing cl.exe."

But the same code will compile fine in later versions of visual studio. Seems they have fixed the bug :)

Monday, April 14, 2008

MessageBox in ExitInstance

Like the problem in displaying the message box in InitInstance of an APP class, there is a problem in displaying the message box in ExitInstance() also. Try the following code..

int CMyApp::ExitInstance()
{
AfxMessageBox( "Some message from CMyApp::ExitInstance" );
return CWinApp::ExitInstance();
}

The messagebox will never appear!!!! After a small investigation, I found that this is beacuse of the WM_QUIT message that exists in the message queue. So removing the WM_QUIT message from the message queue will simply solve the problem. For removing the WM_QUIT, a GetMessage() function in while loop while be enough. So I modified the code as follows..

int CMyApp::ExitInstance()
{
MSG stMsg;
while( GetMessage( &stMsg,0,0,0));
AfxMessageBox( "Some message from CMyApp::ExitInstance" );
return CWinApp::ExitInstance();
}

After this the message box is showing correctly. The Theory is that, when we try to create a window and at that time if a WM_QUIT message exists in the message queue, the window creation will fail. Putting the GetMessage in the while loop will remove the WM_QUIT from the message loop also GetMessage will return false if it encounters a WM_QUIT. Thus it exits from the while loop.

Though we got a soltion, did you thought who send the WM_QUIT message? The WM_QUIT message is normally created using the PostQuitMessage() and in MFC AfxPostQuitMessage() function wrappers PostQuitMessage(). So I put a breakpoint in AfxPostQuitMessage() and waited. Upon clicking the Close button in the dialog, the break point triggered. And the callstack window shows that the CWnd::OnNcDestroy() function called AfxPostQuitMessage().

If you check the CWnd::OnNcDestroy() function, you can find that, it calls the AfxPostQuitMessage upon checking various conditions such as The window closed now is a Main Window, The Current instance is not a dll etc..

Monday, April 7, 2008

When a MessageBox in InitInstance didn't show..

Once I created one utility in which had the below piece of code.


BOOL CMyApp::InitInstance()
{

AfxEnableControlContainer();
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
HANDLE hMutex = CreateMutex( 0, 0, _T("Some_Mutex"));
if( GetLastError() == ERROR_ALREADY_EXISTS )
{
AfxMessageBox( _T("Only one instance of the application can be run"));
CloseHandle( hMutex );
return FALSE;
}
CMyDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
CloseHandle( hMutex );
return FALSE;
}


My purpose was to run only one instance of the application. If more than one instance is run, the second instance will show a message box and exits. Before release of the utility, I some touch ups in the application. Fortunately just before the release I noticed that, if two instance of the application is run, the second instance simply exits without showing that message box.
Then I started to roll back the touch ups one by one. After removing one of them, the message box again showed. And that touch up was the manifest file I added for giving XP look and feel. I searched and searched and finally found out that the problem is because of not calling the InitCommonControls() function. It was right there in the documentation Using Windows XP Visual Styles[^] , but I never followed it.


The actual purpose of the InitCommonControls() is described in The Old New Thing [^]. It says if we didn't call the InitCommonControls() funtion, our application will not be having any reference to the COMCTL32.DLL and therefore will not be loaded while my application start. So when I tries to create a window, the class will not be registered and so the CreateWindow() function will fail.



How ever my doubt was, even with out the InitCommonControls() function, my application dialog was showing correctly. Only the Message box had the problem. InitCommonControls() isn't necessary for the dialog? How ever when I stepped into the source code of the MFC, things became clear. Inside the DoModal() function, it is calling the InitCommonControls(). The AfxDeferRegisterClass MACRO was doing this job.


Now I got another doubt, Since MFC calls the InitCommonControls() function, the COMCTL32.DLL will be statically linked to MFC42.dll and my application is statically linked to the MFC42.dll. So COMCTL32.DLL should definitly load in the beginning itself. But for some reasons even though MFC42.dll was loaded, COMCTL32.DLL didn't get loaded.


The only possibility for such a scenario will be a delay load of COMCTL32.DLL in the MFC42.dll dll. To confirm, I opened the MFC42.dll in PEView. As expected the COMCTL32.DLL was added in the "DELAY IMPORT Address Table".






Let look back to the original problem. "Message box got displayed in normal case even if I didn't call the InitCommonControls()" . So COMCTL32.DLL not need if didn't use manifest?? The answer is no. In windows Some window classes are register by User32.dll( Like button, edit etc ) and some other control( Windows common controls ) are registered by COMCTL32.DLL. But if we add manifest files, user32.dll will not be registering any of the window classes instead COMCTL32.DLL will do all the registrations. If you check the manifest file of the COMCTL32.DLL version 6, you can see the list of window classes versioned in it.

( The file is located in "C:\WINDOWS\WinSxS\Manifests\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a.Manifest" )

So to conclude, what I learned because of message box problem are.


1. Whether or not you are using Manifest file, you should call InitCommonControls() or InitCommonControlsEx().

2. MFC42.dll have set COMCTL32.DLL to delay load. ( But when I checked in MFC8.dll, the delayed loading of COMCTL32 is removed )

3. If we use manifest file, COMCTL32.DLL will doing the registration of all System Classes instead of user32.dll. So it is necessary to ensure that COMCTL32.DLL have loaded before you create a window belonging to system class.

Sunday, March 23, 2008

Find which dll / exe created a window.

The GetWindowModuleFileName() functions can be used to find which exe or dll have created a window. But the problem with this function is that, it will not work across process.

When ever we create a window, we have to pass the an HINSTANCE into it. And later we can use GetWindowLong to get that HINSTANCE. Actually the HINSTANCE is noting but the HMODULE itself. So if we get the hinstance of a window, we can pass this handle to the
GetModuleFileNameEx() and simply get the name of the window from other processes also.


CString MyGetWindowModuleFileName( HANDLE hwindowhandle )
{
CString csModuleName;
DWORD dwProcessId;
GetWindowThreadProcessId( hwindowhandle, &dwProcessId );
HINSTANCEhModule = (HINSTANCE)GetWindowLong( hwindowhandle, GWL_HINSTANCE );
if(hModule == NULL)
{
return csModuleName;
}
HANDLE hProcess = OpenProcess(PROCESS_VM_READPROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
if( hProcess == NULL )
{
return csModuleName;
}
BOOL bReturn = GetModuleFileNameEx( hProcess, hModule, csModuleName.GetBuffer( MAX_PATH), MAX_PATH );
csModuleName.ReleaseBuffer();
CloseHandle(hProcess);
return csModuleName;
}

Thursday, January 3, 2008

WM_DEVICECHANGE problem

In one our Projects at company, we used WM_DEVICECHANGE message to detect the arrival and removal of USB devices. The application was supposed to run on a machine in which will be running along with several other utility applications. Some months after the project delivery, client reported that, sometimes even if a USB device is plugged in, it is not detected. Problem problem.....

After some investigations we found that if we make the window a top-level window (HWND_TOPMOST), there is no such problems. But what’s the relation between the z-order and the above problem. Later we got few more points to identify the relation.

1. The WM_DEVICECHANGE is send to all the top-level windows according to their z-order. That is the window at the top most position receives the message first, then only the window below it and so one.
2. If a window got a WM_DEVICECHANGE and if it didn’t process the message with in a period (in my machine I think it was 20 secs), the message will not reach to the subsequent windows under it.

Now everything became clear to us, some window whose z-order is greater than our application window might have hung or didn’t process the message within 20 seconds. Thus our window didn’t get a chance. Also when we made our window top level it will be one of the first window's to get WM_DEVICECHANGE message so reducing the number of windows above it to get hung. How ever we didn't find a proper solution for this and moved to an alternative method to detect device arrival and removal.

I think windows might not be using the BroadcastSystemMessage() function with the BSF_FORCEIFHUNG flag, while sending the WM_DEVICECHANGE message.