Optimizing Storage for Constant Data

Posted in KB on May 5, 2008 by naveenraj
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.

Loader snaps

Posted in Tip on April 22, 2008 by naveenraj

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 .

Pointer pointing to Stack or Heap ??

Posted in Tip on April 17, 2008 by naveenraj
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 = 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
}

Break application on dll Load

Posted in Tip on April 16, 2008 by naveenraj
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())

 

__asm int 3 in template function ( in VC6 )

Posted in Bug on April 15, 2008 by naveenraj

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 🙂

MessageBox in ExitInstance

Posted in Tip on April 15, 2008 by naveenraj

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..

When a MessageBox in InitInstance didn’t show..

Posted in KB on April 8, 2008 by naveenraj

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.

Find which dll / exe created a window.

Posted in Tip on March 23, 2008 by naveenraj
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;
}

WM_DEVICECHANGE problem

Posted in Bug on January 3, 2008 by naveenraj
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 problem s. 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, the 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.

Bug in Rich Edit control

Posted in Bug on October 31, 2007 by naveenraj

Basically this not a vc++ bug. Its actually a bug in the RichEdit control so the bug belongs to windows.

Check the picture…

What you see inside the red circle is the caret of rich edit control. It passed the boundaries of rich edit control and moved to the dialog.

Step to reproduce.

1. Create a dialog based application and place a rich edit control on it.
2. Give the Multi line and Auto HSCROLL style.
3. Now run the application and click inside the rich edit, and keep on pressing space bar. You can see the caret crossing the boundary of rich edit and starts moving through the dialog.

This problem exists in vista and XP. But I didn’t find a place to report this bug to Microsoft. I searched the whole internet to find some one already reported this problem. But coudn’t find any. I dont know why such a problem haven’t been noticed for the past 12 years( 12 years because I think the problem exists in the rich edit of 95 also ).