Microsoft Visual C++ Tips and Tricks

来源:互联网 发布:淘宝网乐高未来骑士团 编辑:程序博客网 时间:2024/05/16 05:12


by Alan De Smet

If you're stuckusing Microsoft Visual C++, these tips may help make the experience morepleasant. I've been collecting these little tidbits for a while, and decided tocollect them in one spot.

MicrosoftVisual C++ Tips and Tricks

by Alan De Smet

If you're stuckusing Microsoft Visual C++, these tips may help make the experience morepleasant. I've been collecting these little tidbits for a while, and decided tocollect them in one spot. I've chosen to collect them here because I can'tthink of a better spot.

First thing, getyourself a copy of WorkspaceWhiz. Workspace Whiz gives you a nice GUI interface to Exhuberant CTAGS. It also gives you a handy button to switchbetween the header and source files. It's cheap ($10), and makes life better.

Next, getyourself a copy of STLFilt. It's completely free. It significantly cleans upthe garbage error messages Visual C++ generates for STL code. (It does requirePerl,but every developer should have Perl installed anyway. The easiest way to getPerl for Windows is ActiveState's free ActivePerl.

Whenever I referto the "sharedide" directory, you'll need to change it to theappropriate directory. In Visual C++ 5, it's actually called"sharedide" under the directory where you installed VC. In Visual C++6, it's in the "Common\MSDev98" directory under the directory whereyou installed VC.

Show compile duration

Simply add '/Y3'to the command line of VC (In the short cut). You'll now get reports on howlong a compile took in your Build window.

Update 2003-01-10: I haven't had a chance to use Visual Studio .NET yet, but I'm told thatyou can set this option with a switch under Options > Projects > Build.

Teach VC to intelligently expandclasses/structs in debugger

Isn't it neat how VC's debugger knows how to intelligently expandCStrings, CPoints, POINTS, and alot of other stuff? Well, you can teach it tohandle your own structs and classes. Just edit autoexp.dat in sharedide/bin (in thedirectory where Visual Studio is installed.) The format of that file is fairlycomplicated, so I suggest just copying the examples already in the file.

Add user defined keywords for syntaxhighlighting

Why can you set a color for user defined keywords in Tools > Options > Format? Where do you setthe keywords? Easy, just create usertype.dat in the sharedide/bindirectory that Visual Studio is installedin. Put your keywords in that file, one per line.

Custom Tip of the Day

Any files with the extension ".tip" in the sharedide/bin/ide directory where Visual Studio is installed will be read. You can deletethe .tip files Microsoft provides and add your own. You might want to take alook at Microsoft's files to see the format. I personally suggest filling the.tip file with quotes, news, or something more useful and entertaining that theTotDs.

How to use .cc file extensions for C++

Make thefollowing modifications to the registry:

 

HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\TextEditor\Tabs/Language Settings\C/C++

FileExtensions=cpp;cxx;c;h;hxx;hpp;inl;tlh;tli;rc;rc2;cc;cp

 

HKEY_USERS\S-1-5-21-1219703950-274334628-1532313055-1335\Software\Microsoft\DevStudio\6.0\BuildSystem\Components\Platforms\Win32 (x86)\Tools\32-bit C/C++ Compiler for 80x86

Input_Spec=*.c;*.cpp;*.cxx,*.cc,*.cp

 

HKEY_USERS\S-1-5-21-1219703950-274334628-1532313055-1335\Software\Microsoft\DevStudio\6.0\BuildSystem\Components\Tools\<Component 0x3>

Input_Spec=*.c;*.cpp;*.cxx;*.cc;*.cp

Add the flag"/Tp" to the compiler settings for the project.

Removing the "docking"capability from the menus

In Tools > Options..., in the Workspace tab, turn on "Usescreen reader compatible menus". Yourmenus will lose the gripper (the double line on the left edge indicatingdockability), and will stay nailed down like they should. Unfortunately thisalso removes the icons from the menus.

Useful build messages

The followingmacros make it easy to add reminders which are displayed when code is compiled.You can double click on a reminder in the Output Window and jump to the line.Useful for marking TODOs. (Originally from WindowsDeveloper Journal, 1997?)

 

// Statements like:

//             #pragma message(Reminder "Fixthis problem!")

// Which will causemessages like:

//             C:\Source\Project\main.cpp(47):Reminder: Fix this problem!

// to show up duringcompiles.  Note that you can NOT use the

// words"error" or "warning" in your reminders, since it will

// make the IDE thinkit should abort execution.  You candouble

// click on thesemessages and jump to the line in question.

#define Stringize( L)                #L

#define MakeString(M, L )            M(L)

#define $Line                                 \

        MakeString( Stringize, __LINE__ )

#define Reminder                              \

        __FILE__ "(" $Line ") :Reminder: "

Once defined,use like so:

 

#pragmamessage(Reminder "Fix this problem!")

This will createoutput like:

 

C:\Source\Project\main.cpp(47):Reminder: Fix this problem!

Hard code a debugger breakpoint

If you need toinsert a hard breakpoint in your code (perhaps because you need to attach to aprocess), simply add the following line to your code.

__asm int 3;

Tracking GDI resource leaks

Plenty of toolsexist to help track down memory leaks. You've got the debug heap, Rational Purify for Windows, HeapAgent, and other tools. But there aren't any good toolsto help track GDI resource leaks. A resource leak can crash the system underWindows 95 or Windows 98, and can ruin performance on any Windows operatingsystem.

The article"Resource Leaks: Detecting, Locating, andRepairing Your Leaky GDI Code" is the only real help I'vefound. In particular, the article includes a program that tracks currentglobally allocated resources under Windows 95 or Windows 98. You can track whatresources were created between a start and stop points, and display what thoseresources are. Check the article for the download (Leaks.exe).

Update 2003-01-10: The very friendly people at Compuware have pointed out that BoundsChecker will detect GDI resource leaks. At the moment I'm doing Unix developmentwork, so I haven't had a chance to test it myself, but if you're fighting GDIleaks, it might be worth checking out. At the moment it appears to carry a $695price tag. They offer a trial period. (Regrettably of the "give us yourcontact info and we'll contact you about a trial" type.)

Memory Values

Check this page form information on"Funny" Memory Values. In particular:

If you're usingthe debug heap, memory is initialized and cleared with special values.Typically MFC automatically adds something like the following to your .cppfiles to enable it:

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static charTHIS_FILE[] = __FILE__;

#endif

You can findinformation on using the debug heap here.Microsoft defines some of the magic values here.

While using thedebug heap, you'll see the values:

Value

Usage

0xCDCDCDCD

Allocated in heap, but not initialized

0xDDDDDDDD

Released heap memory.

0xFDFDFDFD

"NoMansLand" fences automatically placed at boundary of heap memory. Should never be overwritten. If you do overwrite one, you're probably walking off the end of an array.

0xCCCCCCCC

Allocated on stack, but not initialized

Watch Values

The watch windowhas a number of undocumented or minimally documented features that make it evenmore useful.

Display GetLastError's value and message

You can displaythe value GetLastError() will return by putting "@err" in your watch window. You can see theerror message associated with that value by putting "@err,hr" in your watchwindow. If you've placed an HRESULT in a variable, adding ",hr" to the variable name in the watchwindow will display the associated text.

Display pointer as an array

If you expand apointer and you only get a single item, just add ",n" to the entry inthe watch window where n is the number of elements to expand. For example, ifyou have a foo * pFoo pointing to anarray of ten elements, put pFoo,10 in your watch window to see all of the element. This can be useful to viewparts of a large array. If pFoo points to an array of 5,000 elements, you mightuse (pFoo + 2000),10 to see elements2000 through 2009.

Debug checked casts

If you wantmaximum safety, you should always use dynamic_cast. However, if you feel you must optimize away those costs, use this versionof checked_cast. It will ASSERT on a bad cast in Debug builds, but not do theslightly more expensive dynamic_cast in Release builds.

 

// checked_cast -Uses fast static_cast in Release build,

// but checks castwith an ASSERT in Debug.

//

// Typical usage:

//   class Foo { /* ... */  };

//   class Bar : public Foo { /* ... */  };

//   Foo * pFoo = new Bar;

//   Bar * pBar = checked_cast<Bar*>(pFoo);

 

template <classTypeTo, class TypeFrom>                                        

TypeTochecked_cast(TypeFrom p)                                                 

{

       ASSERT(dynamic_cast<TypeTo>(p));                                       

        returnstatic_cast<TypeTo>(p);                                         

}                                                                              

Don't use SourceSafe

SourceSafe isproblematic revision control system. The integration with Visual Studio is not worth the trouble. There are better solutionsavailable. I've written a page with specific details on why Visual SourceSafe is a bad choice.


Unverified

These are notestaken by a David Carley from a video of a talk given by a Microsoft VisualStudio developer. Unfortunately the original video is no longer available (orat least hidden). I haven't verified most of these.

Avoiding Stepping Into Things

It's oftenuseful to avoid stepping into some common code like constructors or overloadedoperators. autoexp.dat provides thiscapability. Add a section called "[ExecutionControl]". Add keyswhere the key is the function name and the value is "NoStepInto". You canspecify an asterisk (*) as a wildcardas the first set of colons for a namespace or class.

autoexp.dat is only read on Visual Studio's start up.

To ignore thefunction myfunctionname, and all calls to the class CFoo:

 

[ExecutionControl]

myfunctionname=NoStepInto

CFoo::*=NoStepInto

To ignoreconstruction and assignment of MFC CStrings: (Notice the extra = inCString::operator=.)

 

[ExecutionControl]

CString::CString=NoStepInto

CString::operator==NoStepInto

To ignore allATL calls:

 

[ExecutionControl]

ATL::*=NoStepInto

Function Evaluation

 

    Call program code from debugger

        Use quickwatch window, not watchwindow.

        e.g. DumpInfo (pFoo)

    Great for debug data

       Use OutputDebugString or printf

    Limitations

        20 seconds max.

        Terminate on exception.

        Only one thread

Multi-Threaded Debugging

 

    Current Thread ID:

        NT4: dw @tib+24   (thread information block)

        Win9x: FS register is unique per thread

        You can use this to set a break pointto only fire on a

        given thread

Naming Threads

Use "SetThreadName". The name islimited to 9 characters. SetThreadName fires an exception, which the debuggerwill catch and use to name the thread. The name will appears in Debug >Threads dialog.

 

#defineMS_VC_EXCEPTION 0x406d1388

 

typedef structtagTHREADNAME_INFO

{

    DWORD dwType;        // must be 0x1000

    LPCSTR szName;       // pointer to name (in same addr space)

    DWORDdwThreadID;    // thread ID (-1 callerthread)

    DWORD dwFlags;       // reserved for future use, most be zero

} THREADNAME_INFO;

 

voidSetThreadName(DWORD dwThreadID, LPCTSTR szThreadName)

{

    THREADNAME_INFO info;

    info.dwType = 0x1000;

    info.szName = szThreadName;

    info.dwThreadID = dwThreadID;

    info.dwFlags = 0;

 

    __try

    {

        RaiseException(MS_VC_EXCEPTION, 0,sizeof(info) / sizeof(DWORD),

(DWORD *)&info);

    }

    except (EXCEPTION_CONTINUE_EXECUTION)

    {

    }

}

Win32 Exceptions

 

        If unhandled, kills app

        Debug > Exceptions dialog

        Stop Always or Stop if not Handled.

            Debugger sees exceptions beforeapp, has control

            Stop Always lets you see wherethrown

            Then, step, see where caught.

        Can add new exceptions

            watch output window

        Decoding C++ Exceptions

            Install ntdll.dbg towinnt\symbols\dll

            Set "Microsoft C++Exception" to Stop Always

Breakpoints in System DLLs

 

    System DLLs

        Windows NT only

            Can't just use the function name.

            Need the dll name too

        Determine DLL

            From Help

            or, grep in lib\win32api.csv

        Determinte the exact, unmangled name

        Set BP on {,,dllname}Function   <=- special syntax

        Find true function name.

            Use dumpbin

            May need to enable "Load COFF& Exports" in 6.0

Breakpoint on certain argument values

1.  Set breakpoint

2.  Determine stack offset to argument (seedisassembly window)

3.  Set condition e.g. dw esp+0x8 == 0xFFFFFFFF

Data Breakpoints

Data breakpointsare very powerful, but suffers from a confusing interface. Avoid entering"emulation" mode if possible, it's very slow.

It's oftenuseful to break on an address: "*(long*)0x1234ABCD, length = 1".

The debugger canonly support 4 hardware data breakpoints. If you use expressions (a + b),debugger uses emulation mode.

Data breakpointsonly work on x86 processors, and can't catch kernel mode writes.

Data breakpointscan trigger operating system bugs. A data breakpoint set in one process mightnot be unset when the OS switches processes. This can cause other applicationsto crash. Windows 9x breaks often. Windows NT breaks less often. Reboot when ithappens.

 

    CountBPs

        Stop on the Nth iteration

        To Help find N:

            Set BP w/ very large count(C==10000)

            Run until your app crashes

            Look at count value (X)

            Set count BP on C-X-1

    By Name

        Stays put through edits (as opposed toF9, for

        file/line number BPs)

Memory Leaks

 

    Docs are confusing

        Indexed entries talk about MFC

        No clear description

        Go to "Visual C++Documentation/Using Visual C++/Visual

            C++ ProgrammersGuide/Debugging/Debugging

            Techniques.Problems andSolutions/Solving Buffer

            Overwrites and Memory Leaks"(6.0)

    Include order is important

        Some things redefine malloc and free,etc.

    Step 1, include in global header file

        #define _CRTDBG_MAP_ALLOC

        #include <stdlib.h>

        #include <crtdbg.h>

    Step 2, enable checks in WinMain:

        // Enables tracking and reporting onshutdown.

        _CrtSetDbgFlag (

            _CRTDBG_ALLOC_MEM_DF |

            _CRTDBG_LEAK_CHECK_DF);

        _CrtSetReportMode ( _CRT_ERROR,

            _CRTDBG_MODE_DEBUG);

 

        It may list file/line number

        Will list leak number

            set {,,msvcrtd.dll}_crtBreakAlloc =n (leak number)

        Or, look for ASCII clues.

Memory Corruption

 

    Heap Corruption

        Enable heap checking (slow)

            {,,msvcrtd.dll}_crtDbgFlag = 5

    Data BPs may be useful

Optimized Code

 

    It's hard

        Compile with /Zi

    Variables vanish or are wrong

        Use disassembly window for truth

    Arguments usually OK except

        this

        fastcall

    Just find your bugs in Debug!  8)

Casting in the debugger

 

    Need correct type name

        Debugger doesn't know typedefs

        To find the true typename,

            Add variable to watch, RClick,choose properties

    Scoping:

        variable defined in current DLL, typedefined in another

        DLL:

        {,,foo.dll}(CMyClass *){*}pObject

        pObject is local, CMyClass defined infoo.dll

Modules Window

 

    Debug.Modules

    Sort by:

        Module name

        Address range

            Useful for finding out what moduleyou're in

                Find DLL of EIP

        Full path

            Ensure you're using the correct DLL

        Load order (default)

Debug Works, Release Doesn't

·  Uninitialized variables

o     Often 0 used in debug builds

o     Unless /GZ switch is enabled

·  Under/Overruns of memory

o     use debug heap (running in debugger on NT)

·  Wrong calling convention (esp.GetProcAddress)

o     Use /GZ in compiler

·  Optimizer unforgiving

·  Overwriting locals more likely

o     Locals packed on stack

o     Locals reused

It works When I Don't use the Debugger

 

    Windows NT uses debug heap under debugger

        To avoid, attach to process, ratherthan launching under

        debugger.

    Thread timing different

    PATH may be different (when lauched underMSDEV, vs shell)

        Call GetEnvironmentString in app tocheck.

Timing Code

Add two watches

 

@clk

@clk = 0

Watches areeval'd top to bottom. First one tells you the value of clock, second resets it.Each step will then update these values, and you can do simple profiling. Notgood for assembly timing, because of debugger overhead.

Edit And Continue

 

    Works on any builds

        Just use /ZI

    use SetNextStatement before you edit.

        either set it to a block before thesection you want to

        edit, or, step out of the function,then step back in.

    Beware if you copy binaries

        Auto-relink only updates the target ofthe build, not the

        currently running copy.

        Your only warning is in the Outputwindow

 

    Poor Man's Edit & Continue

        0x90 = NOP

            Use in the disassmebly window to"comment-out" chunks

            of code

        0x74, 0x75 == JE, JNE

            Use to switch the directional senseof an if

            statement.

Disassembly Tricks

 

    Disambiguation dialog is annoying

        Choose any

        Ctrl+G (goto address) EIP

        Goes to current location.

Remote Debugging Made Easy

 

    1. Local Machine

        Build

        Share directory to application

        Map back to local machine (O:)

        Build.Remote

            TCP/IP

            Settings.Machine

        Project.Settings.Debug

            Remote path = O:\foo\bar.exe

    2. Remote machine:

        Install MSVCMON

            (you can Just install VC)

            (or not, if you want a very cleanmachine)

        Map share to same letter as localmachine

            Makes finding DLLs easier

        Launch MSVCMON on remote

            Click Connect

            ignore all options

    3. Start debugging

        Step & Go OK, no attach

        Default DLL path should be correct(VC6)

COM Debugging

 

    Demo

        eax, hr

            Return values are in eax.  If you know it's an

            HRESULT, you can do"eax,hr" and see the error

            message associated with thatHRESULT.

        ,wm for window messages

        @err

            Use this in the watch window todisplay the value

            that GetLastError would return.

        @err, hr will show the msg associatedwith the

            GetLastError value.

        GUIDS and VARIANTs decoded

            New in VC 6.0

        Make sure "Display UnicodeStrings" is enabled

            in the options to show BSTRs etc.

Verify validity of COM object

 

// Verify that apointer to a COM object is still valid

//

// Usage:

//   VERIFY_COM_INTERFACE(pFoo);

//

template <classQ>

voidVERIFY_COM_INTERFACE (Q *p)

{

#   ifdef DEBUG

        p->AddRef();

        p->Release();

#   endif

}

Verify validity of a BSTR

 

// Verify that aBSTER really is a BSTR and is handled correctly

// Warning! Fails onBSTRs which contain embedded nulls

// Usage:

//  VERIFY_BSTR(bstrName)

//

#ifdef DEBUG

#    define VERIFY_BSTR(bstr) do {    \

        ASSERT(SysStringLen(bstr) ==wcslen(bstr)); \

     } while (0)

#else

#    define VERIFY_BSTR(bstr) do {} while (0);

#endif

Contact webmaster - Copyright ©2002 (2002)

 

I've chosen to collect them here because I can'tthink of a better spot.

First thing, getyourself a copy of WorkspaceWhiz. Workspace Whiz gives you a nice GUI interface to Exhuberant CTAGS. It also gives you a handy button to switchbetween the header and source files. It's cheap ($10), and makes life better.

Next, getyourself a copy of STLFilt. It's completely free. It significantly cleans upthe garbage error messages Visual C++ generates for STL code. (It does requirePerl,but every developer should have Perl installed anyway. The easiest way to getPerl for Windows is ActiveState's free ActivePerl.

Whenever I referto the "sharedide" directory, you'll need to change it to theappropriate directory. In Visual C++ 5, it's actually called"sharedide" under the directory where you installed VC. In Visual C++6, it's in the "Common\MSDev98" directory under the directory whereyou installed VC.

Show compile duration

Simply add '/Y3'to the command line of VC (In the short cut). You'll now get reports on howlong a compile took in your Build window.

Update 2003-01-10: I haven't had a chance to use Visual Studio .NET yet, but I'm told thatyou can set this option with a switch under Options > Projects > Build.

Teach VC to intelligently expandclasses/structs in debugger

Isn't it neat how VC's debugger knows how to intelligently expandCStrings, CPoints, POINTS, and alot of other stuff? Well, you can teach it tohandle your own structs and classes. Just edit autoexp.dat in sharedide/bin (in thedirectory where Visual Studio is installed.) The format of that file is fairlycomplicated, so I suggest just copying the examples already in the file.

Add user defined keywords for syntaxhighlighting

Why can you set a color for user defined keywords in Tools > Options > Format? Where do you setthe keywords? Easy, just create usertype.dat in the sharedide/bindirectory that Visual Studio is installedin. Put your keywords in that file, one per line.

Custom Tip of the Day

Any files with the extension ".tip" in the sharedide/bin/ide directory where Visual Studio is installed will be read. You can deletethe .tip files Microsoft provides and add your own. You might want to take alook at Microsoft's files to see the format. I personally suggest filling the.tip file with quotes, news, or something more useful and entertaining that theTotDs.

How to use .cc file extensions for C++

Make thefollowing modifications to the registry:

 

HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\TextEditor\Tabs/Language Settings\C/C++

FileExtensions=cpp;cxx;c;h;hxx;hpp;inl;tlh;tli;rc;rc2;cc;cp

 

HKEY_USERS\S-1-5-21-1219703950-274334628-1532313055-1335\Software\Microsoft\DevStudio\6.0\BuildSystem\Components\Platforms\Win32 (x86)\Tools\32-bit C/C++ Compiler for 80x86

Input_Spec=*.c;*.cpp;*.cxx,*.cc,*.cp

 

HKEY_USERS\S-1-5-21-1219703950-274334628-1532313055-1335\Software\Microsoft\DevStudio\6.0\BuildSystem\Components\Tools\<Component 0x3>

Input_Spec=*.c;*.cpp;*.cxx;*.cc;*.cp

Add the flag"/Tp" to the compiler settings for the project.

Removing the "docking"capability from the menus

In Tools > Options..., in the Workspace tab, turn on "Usescreen reader compatible menus". Yourmenus will lose the gripper (the double line on the left edge indicatingdockability), and will stay nailed down like they should. Unfortunately thisalso removes the icons from the menus.

Useful build messages

The followingmacros make it easy to add reminders which are displayed when code is compiled.You can double click on a reminder in the Output Window and jump to the line.Useful for marking TODOs. (Originally from WindowsDeveloper Journal, 1997?)

 

// Statements like:

//             #pragma message(Reminder "Fixthis problem!")

// Which will causemessages like:

//             C:\Source\Project\main.cpp(47):Reminder: Fix this problem!

// to show up duringcompiles.  Note that you can NOT use the

// words"error" or "warning" in your reminders, since it will

// make the IDE thinkit should abort execution.  You candouble

// click on thesemessages and jump to the line in question.

#define Stringize( L)                #L

#define MakeString(M, L )            M(L)

#define $Line                                 \

        MakeString( Stringize, __LINE__ )

#define Reminder                              \

        __FILE__ "(" $Line ") :Reminder: "

Once defined,use like so:

 

#pragmamessage(Reminder "Fix this problem!")

This will createoutput like:

 

C:\Source\Project\main.cpp(47):Reminder: Fix this problem!

Hard code a debugger breakpoint

If you need toinsert a hard breakpoint in your code (perhaps because you need to attach to aprocess), simply add the following line to your code.

__asm int 3;

Tracking GDI resource leaks

Plenty of toolsexist to help track down memory leaks. You've got the debug heap, Rational Purify for Windows, HeapAgent, and other tools. But there aren't any good toolsto help track GDI resource leaks. A resource leak can crash the system underWindows 95 or Windows 98, and can ruin performance on any Windows operatingsystem.

The article"Resource Leaks: Detecting, Locating, andRepairing Your Leaky GDI Code" is the only real help I'vefound. In particular, the article includes a program that tracks currentglobally allocated resources under Windows 95 or Windows 98. You can track whatresources were created between a start and stop points, and display what thoseresources are. Check the article for the download (Leaks.exe).

Update 2003-01-10: The very friendly people at Compuware have pointed out that BoundsChecker will detect GDI resource leaks. At the moment I'm doing Unix developmentwork, so I haven't had a chance to test it myself, but if you're fighting GDIleaks, it might be worth checking out. At the moment it appears to carry a $695price tag. They offer a trial period. (Regrettably of the "give us yourcontact info and we'll contact you about a trial" type.)

Memory Values

Check this page form information on"Funny" Memory Values. In particular:

If you're usingthe debug heap, memory is initialized and cleared with special values.Typically MFC automatically adds something like the following to your .cppfiles to enable it:

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static charTHIS_FILE[] = __FILE__;

#endif

You can findinformation on using the debug heap here.Microsoft defines some of the magic values here.

While using thedebug heap, you'll see the values:

Value

Usage

0xCDCDCDCD

Allocated in heap, but not initialized

0xDDDDDDDD

Released heap memory.

0xFDFDFDFD

"NoMansLand" fences automatically placed at boundary of heap memory. Should never be overwritten. If you do overwrite one, you're probably walking off the end of an array.

0xCCCCCCCC

Allocated on stack, but not initialized

Watch Values

The watch windowhas a number of undocumented or minimally documented features that make it evenmore useful.

Display GetLastError's value and message

You can displaythe value GetLastError() will return by putting "@err" in your watch window. You can see theerror message associated with that value by putting "@err,hr" in your watchwindow. If you've placed an HRESULT in a variable, adding ",hr" to the variable name in the watchwindow will display the associated text.

Display pointer as an array

If you expand apointer and you only get a single item, just add ",n" to the entry inthe watch window where n is the number of elements to expand. For example, ifyou have a foo * pFoo pointing to anarray of ten elements, put pFoo,10 in your watch window to see all of the element. This can be useful to viewparts of a large array. If pFoo points to an array of 5,000 elements, you mightuse (pFoo + 2000),10 to see elements2000 through 2009.

Debug checked casts

If you wantmaximum safety, you should always use dynamic_cast. However, if you feel you must optimize away those costs, use this versionof checked_cast. It will ASSERT on a bad cast in Debug builds, but not do theslightly more expensive dynamic_cast in Release builds.

 

// checked_cast -Uses fast static_cast in Release build,

// but checks castwith an ASSERT in Debug.

//

// Typical usage:

//   class Foo { /* ... */  };

//   class Bar : public Foo { /* ... */  };

//   Foo * pFoo = new Bar;

//   Bar * pBar = checked_cast<Bar*>(pFoo);

 

template <classTypeTo, class TypeFrom>                                        

TypeTochecked_cast(TypeFrom p)                                                 

{

       ASSERT(dynamic_cast<TypeTo>(p));                                       

        returnstatic_cast<TypeTo>(p);                                         

}                                                                              

Don't use SourceSafe

SourceSafe isproblematic revision control system. The integration with Visual Studio is not worth the trouble. There are better solutionsavailable. I've written a page with specific details on why Visual SourceSafe is a bad choice.


Unverified

These are notestaken by a David Carley from a video of a talk given by a Microsoft VisualStudio developer. Unfortunately the original video is no longer available (orat least hidden). I haven't verified most of these.

Avoiding Stepping Into Things

It's oftenuseful to avoid stepping into some common code like constructors or overloadedoperators. autoexp.dat provides thiscapability. Add a section called "[ExecutionControl]". Add keyswhere the key is the function name and the value is "NoStepInto". You canspecify an asterisk (*) as a wildcardas the first set of colons for a namespace or class.

autoexp.dat is only read on Visual Studio's start up.

To ignore thefunction myfunctionname, and all calls to the class CFoo:

 

[ExecutionControl]

myfunctionname=NoStepInto

CFoo::*=NoStepInto

To ignoreconstruction and assignment of MFC CStrings: (Notice the extra = inCString::operator=.)

 

[ExecutionControl]

CString::CString=NoStepInto

CString::operator==NoStepInto

To ignore allATL calls:

 

[ExecutionControl]

ATL::*=NoStepInto

Function Evaluation

 

    Call program code from debugger

        Use quickwatch window, not watchwindow.

        e.g. DumpInfo (pFoo)

    Great for debug data

       Use OutputDebugString or printf

    Limitations

        20 seconds max.

        Terminate on exception.

        Only one thread

Multi-Threaded Debugging

 

    Current Thread ID:

        NT4: dw @tib+24   (thread information block)

        Win9x: FS register is unique per thread

        You can use this to set a break pointto only fire on a

        given thread

Naming Threads

Use "SetThreadName". The name islimited to 9 characters. SetThreadName fires an exception, which the debuggerwill catch and use to name the thread. The name will appears in Debug >Threads dialog.

 

#defineMS_VC_EXCEPTION 0x406d1388

 

typedef structtagTHREADNAME_INFO

{

    DWORD dwType;        // must be 0x1000

    LPCSTR szName;       // pointer to name (in same addr space)

    DWORDdwThreadID;    // thread ID (-1 callerthread)

    DWORD dwFlags;       // reserved for future use, most be zero

} THREADNAME_INFO;

 

voidSetThreadName(DWORD dwThreadID, LPCTSTR szThreadName)

{

    THREADNAME_INFO info;

    info.dwType = 0x1000;

    info.szName = szThreadName;

    info.dwThreadID = dwThreadID;

    info.dwFlags = 0;

 

    __try

    {

        RaiseException(MS_VC_EXCEPTION, 0,sizeof(info) / sizeof(DWORD),

(DWORD *)&info);

    }

    except (EXCEPTION_CONTINUE_EXECUTION)

    {

    }

}

Win32 Exceptions

 

        If unhandled, kills app

        Debug > Exceptions dialog

        Stop Always or Stop if not Handled.

            Debugger sees exceptions beforeapp, has control

            Stop Always lets you see wherethrown

            Then, step, see where caught.

        Can add new exceptions

            watch output window

        Decoding C++ Exceptions

            Install ntdll.dbg towinnt\symbols\dll

            Set "Microsoft C++Exception" to Stop Always

Breakpoints in System DLLs

 

    System DLLs

        Windows NT only

            Can't just use the function name.

            Need the dll name too

        Determine DLL

            From Help

            or, grep in lib\win32api.csv

        Determinte the exact, unmangled name

        Set BP on {,,dllname}Function   <=- special syntax

        Find true function name.

            Use dumpbin

            May need to enable "Load COFF& Exports" in 6.0

Breakpoint on certain argument values

1.  Set breakpoint

2.  Determine stack offset to argument (seedisassembly window)

3.  Set condition e.g. dw esp+0x8 == 0xFFFFFFFF

Data Breakpoints

Data breakpointsare very powerful, but suffers from a confusing interface. Avoid entering"emulation" mode if possible, it's very slow.

It's oftenuseful to break on an address: "*(long*)0x1234ABCD, length = 1".

The debugger canonly support 4 hardware data breakpoints. If you use expressions (a + b),debugger uses emulation mode.

Data breakpointsonly work on x86 processors, and can't catch kernel mode writes.

Data breakpointscan trigger operating system bugs. A data breakpoint set in one process mightnot be unset when the OS switches processes. This can cause other applicationsto crash. Windows 9x breaks often. Windows NT breaks less often. Reboot when ithappens.

 

    CountBPs

        Stop on the Nth iteration

        To Help find N:

            Set BP w/ very large count(C==10000)

            Run until your app crashes

            Look at count value (X)

            Set count BP on C-X-1

    By Name

        Stays put through edits (as opposed toF9, for

        file/line number BPs)

Memory Leaks

 

    Docs are confusing

        Indexed entries talk about MFC

        No clear description

        Go to "Visual C++Documentation/Using Visual C++/Visual

            C++ ProgrammersGuide/Debugging/Debugging

            Techniques.Problems andSolutions/Solving Buffer

            Overwrites and Memory Leaks"(6.0)

    Include order is important

        Some things redefine malloc and free,etc.

    Step 1, include in global header file

        #define _CRTDBG_MAP_ALLOC

        #include <stdlib.h>

        #include <crtdbg.h>

    Step 2, enable checks in WinMain:

        // Enables tracking and reporting onshutdown.

        _CrtSetDbgFlag (

            _CRTDBG_ALLOC_MEM_DF |

            _CRTDBG_LEAK_CHECK_DF);

        _CrtSetReportMode ( _CRT_ERROR,

            _CRTDBG_MODE_DEBUG);

 

        It may list file/line number

        Will list leak number

            set {,,msvcrtd.dll}_crtBreakAlloc =n (leak number)

        Or, look for ASCII clues.

Memory Corruption

 

    Heap Corruption

        Enable heap checking (slow)

            {,,msvcrtd.dll}_crtDbgFlag = 5

    Data BPs may be useful

Optimized Code

 

    It's hard

        Compile with /Zi

    Variables vanish or are wrong

        Use disassembly window for truth

    Arguments usually OK except

        this

        fastcall

    Just find your bugs in Debug!  8)

Casting in the debugger

 

    Need correct type name

        Debugger doesn't know typedefs

        To find the true typename,

            Add variable to watch, RClick,choose properties

    Scoping:

        variable defined in current DLL, typedefined in another

        DLL:

        {,,foo.dll}(CMyClass *){*}pObject

        pObject is local, CMyClass defined infoo.dll

Modules Window

 

    Debug.Modules

    Sort by:

        Module name

        Address range

            Useful for finding out what moduleyou're in

                Find DLL of EIP

        Full path

            Ensure you're using the correct DLL

        Load order (default)

Debug Works, Release Doesn't

·  Uninitialized variables

o     Often 0 used in debug builds

o     Unless /GZ switch is enabled

·  Under/Overruns of memory

o     use debug heap (running in debugger on NT)

·  Wrong calling convention (esp.GetProcAddress)

o     Use /GZ in compiler

·  Optimizer unforgiving

·  Overwriting locals more likely

o     Locals packed on stack

o     Locals reused

It works When I Don't use the Debugger

 

    Windows NT uses debug heap under debugger

        To avoid, attach to process, ratherthan launching under

        debugger.

    Thread timing different

    PATH may be different (when lauched underMSDEV, vs shell)

        Call GetEnvironmentString in app tocheck.

Timing Code

Add two watches

 

@clk

@clk = 0

Watches areeval'd top to bottom. First one tells you the value of clock, second resets it.Each step will then update these values, and you can do simple profiling. Notgood for assembly timing, because of debugger overhead.

Edit And Continue

 

    Works on any builds

        Just use /ZI

    use SetNextStatement before you edit.

        either set it to a block before thesection you want to

        edit, or, step out of the function,then step back in.

    Beware if you copy binaries

        Auto-relink only updates the target ofthe build, not the

        currently running copy.

        Your only warning is in the Outputwindow

 

    Poor Man's Edit & Continue

        0x90 = NOP

            Use in the disassmebly window to"comment-out" chunks

            of code

        0x74, 0x75 == JE, JNE

            Use to switch the directional senseof an if

            statement.

Disassembly Tricks

 

    Disambiguation dialog is annoying

        Choose any

        Ctrl+G (goto address) EIP

        Goes to current location.

Remote Debugging Made Easy

 

    1. Local Machine

        Build

        Share directory to application

        Map back to local machine (O:)

        Build.Remote

            TCP/IP

            Settings.Machine

        Project.Settings.Debug

            Remote path = O:\foo\bar.exe

    2. Remote machine:

        Install MSVCMON

            (you can Just install VC)

            (or not, if you want a very cleanmachine)

        Map share to same letter as localmachine

            Makes finding DLLs easier

        Launch MSVCMON on remote

            Click Connect

            ignore all options

    3. Start debugging

        Step & Go OK, no attach

        Default DLL path should be correct(VC6)

COM Debugging

 

    Demo

        eax, hr

            Return values are in eax.  If you know it's an

            HRESULT, you can do"eax,hr" and see the error

            message associated with thatHRESULT.

        ,wm for window messages

        @err

            Use this in the watch window todisplay the value

            that GetLastError would return.

        @err, hr will show the msg associatedwith the

            GetLastError value.

        GUIDS and VARIANTs decoded

            New in VC 6.0

        Make sure "Display UnicodeStrings" is enabled

            in the options to show BSTRs etc.

Verify validity of COM object

 

// Verify that apointer to a COM object is still valid

//

// Usage:

//   VERIFY_COM_INTERFACE(pFoo);

//

template <classQ>

voidVERIFY_COM_INTERFACE (Q *p)

{

#   ifdef DEBUG

        p->AddRef();

        p->Release();

#   endif

}

Verify validity of a BSTR

 

// Verify that aBSTER really is a BSTR and is handled correctly

// Warning! Fails onBSTRs which contain embedded nulls

// Usage:

//  VERIFY_BSTR(bstrName)

//

#ifdef DEBUG

#    define VERIFY_BSTR(bstr) do {    \

        ASSERT(SysStringLen(bstr) ==wcslen(bstr)); \

     } while (0)

#else

#    define VERIFY_BSTR(bstr) do {} while (0);

#endif

Contact webmaster - Copyright ©2002 (2002)

 

原创粉丝点击