Tips for BC++ 5.0

What'sBC5 IDEOWL 5.0ScriptsClasslibBack to FAQ Page

Index

This page provides some IDE and OWL 5.0 tips. If you have tips you think should be listed here then please e-mail us with your suggestions. Tips should be concise and in a form that can be implemented with a minimum amount of editing.

Installation Tip
Where you are getting severe problems running BC5, it may be due to registry entries being messed up. To correct these, you can try using the install program. There is an option on the install screen to select an "Only icons/System files/registry" installation. This will ensure that the correct registrations are in place, overwriting any faulty ones. (It will not remove any superfluous entries though). Worth a try before de-installing and re-installing.


Index

IDE Tips
Search Mode in the IDE Editor Windows
Drag and Drop a DLL Onto the IDE
Importing the CodeGuard Log in 16-bit and 32-bit Targets
Reducing Pre-Compiled Header Sizes in 32-bit Apps
Undocumented IDE ToolTips
Autodepenency Problems?
IDE Always Makes a Certain Node
Save Time by Recording IDE Keystrokes
Referenced Modules Appear in Runtime Message Window
Faster App Load Time in the IDE Debugger
Pick and Choose Building of Nodes
Searching for Project Nodes
Startup Exceptions (TDW & TDW32)
Debugger Able to Continue After Exceptions Raised

OWL 5.0 Tips
Overriding Default Exception Behaviour In OWL
Running only a Single Instance under Win32
Dockable Toolbars - Somewhere to Call Home
Dockable Toolbars - Getting Location
TNoteTab - A Better Tab Control
Defining Subkeys with TRegKey
The TCmdLine Class (Undocumented)
The TSystem Class (Undocumented)
The TUIMetric Class (Undocumented)
TTreeWindow - Getting the Text From an Item
TModuleProc Templates Replace LoadLibrary()/GetProcAddress()
Grab Notification Messages at the Control
Easy Speed Menus

ObjectScript
Replacement for EDITSIZE.SPP Script
Quickie Method to Attatch a Script to a Keystroke
BC5 Sound Scheme Script
Autosave Editor Files Prior to Debugger Running
String Functions Appear to be Missing
Removing Messages from the Message Window Before a Debug Session.
Syntax Highlighting for Scripts
Running Your Own Scripts on IDE Startup
Script to Check WINHELP.INI for Errors

IDE Tips

Search Mode in the IDE Editor Windows
In the IDE you can enter Search Mode by typing Ctrl-S. Now type a key on the keyboard. The editor highlights the next occurance of that key. Type another key and the editor highlights the next occurance of the combination of those two keys. Type another key and the editor highlights the next occurance of those three characters, etc. The search is case sensitive. If no match is found then the IDE beeps to indicate no match. Exit Search Mode by hitting the ESC key or any arrow key.

Drag and Drop a DLL Onto the IDE
If you drag and drop a DLL containing resources onto the BC++ 5.0 IDE the resource editor will load and the DLL's resources will be displayed. You can also drag and drop .ico, .bmp, .rc, .res, .cur, .cgl, or any text file.

Importing the CodeGuard Log in 16-bit and 32-bit Targets
When your CodeGuard enabled application encounters an error a log file is created that contains information regarding the error. This is true whether the program is run from the IDE or outside of the IDE. The log file has the same name as the project and has a .cgl extension. The log file is simply a text file that contains information about the error. You can read the log file as-is but the BC5 IDE has a more useful way of dealing with the CodeGuard log file. You can import the log file into the message window. You can import the .cgl in one of two ways:

- From the project window's speed menu, choose "Import CodeGuard Log"
- Drag the .cgl file from Explorer or FileManager and drop it on the message window

Once the log file is imported to the message window the CodeGuard information shows up under the Runtime tab. You can then double click on a CodeGuard message and the associated line in your source file will be displayed in an editor window. Even though 16-bit programs cannot be debugged in the IDE debugger, this technique still applies to 16-bit programs as well as 32-bit programs.

Reducing Pre-Compiled Header Sizes in 32-bit Apps
If your 32-bit apps do not use OLE you can reduce the pre-compiled header sizes by #defining WIN32_LEAN_AND_MEAN for the project. This will prevent the OLE headers from being accessed. You can either add a #define to your headers, or add the WIN32_LEAN_AND_MEAN define to the Defines section for the project (Options | Project | Compiler | Defines). This should also reduce the time of your builds.

Note: If you are building an OWL app then you must #include WINDOWS.H and SHELLAPI.H before any OWL headers that your project uses.

Undocumented IDE ToolTips
You know that if you place the mouse cursor over a button on the IDE's control bar that you will get a tool tip describing what the button does. But there's more to it: If you press and hold the Ctrl key before placing the cursor over a button you will get the name of the cScript function that corresponds to the button. For example holding Ctrl and placing the cursor over the File Open button will yield tool the tool tip text, "IDE.FileOpen();"

Autodependencies Problems?
If your build dependencies are cured by switching to Dependencies | Use instead of Cache, try this cure. Run the tool StripAutodependencies against the top node of your project. (Add a tool by selecting Advanced | Add To Tools Menu from the Options | Tools... dialog)
.

The IDE Always Makes a Certain Node
If the IDE always makes a node, check the message in the Buildtime page of the messages window. This will tell you what file the rebuild is due to. Check the spelling carefully. Then expand the [.cpp] node that is getting rebuilt. The chances are that the dependency is an [.h] node that is no longer used but is still listed under the [.cpp] node and the source has also been deleted from the disk. You can safely delete the [.h] node.

Save Time by Recording IDE Keystrokes
Keystroke recording works for the project window. If you want to turn on and off CodeGuard or some other option, it is tedious to do this for multiple targets. Without even using scripting you can do this by:

1. Get all the nodes contracted to just show the target
2. Turn on record Ctrl-Shift-R
3. Use alt-F10 to open up the speedmenu, use the arrow key to go to TargetExpert, press Enter
4. Tab/Shift Tab to the option you want to change
5. Use space to change the check boxes
6. Press enter to close the dialog
7. Use "-" to close the target node (which the IDE expands for some reason)
8. Use a down arrow to move to the next node
9. Press Ctrl-Shift-R to turn off record
10. Press Ctrl-Shift-P to replay against subsequent nodes.

By cunning use of the keyboard, you can use this technique for a number of tasks.

Referenced Modules Appear in Runtime Message Window
Prior to version 5.0 of BC++ if you wanted to know what DLLs your program relied on you had to run TDUMP on the final .exe or use a similar utility. Now all of the DLLs that your program loads are listed in the message window under the Runtime tab.

Faster App Load Time in the IDE Debugger
Running a program from the IDE can be tedious to kick off because the IDE always does a dependency check. There is a simple workaround, add another identical target, choose Options | Project | Make and mark the target as Never Build. (You don't need to add any source files underneath the node). You can then run this node instead and it will pick up the source and debug as if you were running the original node.

Pick and Choose Building of Nodes
Under V5.0, you can select both a DLL node and an EXE node at the same time to make or build in one pass. Under 4.0, you could not build mixed nodes at the same time.

Searching for Project Nodes
If you have a large project, do you sometimes lose your node? The project view has an incremental search. With a node highlighted, simply type the text you want to find in the project window. If the first match is ambiguous, use Ctrl-S to search forward to the next match. Use Esc to quit the search. The nodes must be visible. Use * to expand all the branches of a project.

Exceptions on Startup
Under TD32 or TDW, there is an option to show exceptions when they are raised. This is not a GPF! You can continue execution with F9. With an AppExpert application with registration enabled, exceptions will be raised AND HANDLED under NT 3.51 as not all the standard keys aliased in TRegKey are present. You can safely ignore these exceptions. You can use Options | Exceptions and set both settings to None and you will not get the exception raised notification. As a general point, exceptions and GPFs during startup are caused by static (or global) constructors being called.

Debugger Able to Continue After Exceptions Raised
In the IDE debugger when an exception is raised you will get an "Access Violation" dialog box. At this point you may reset the process (Debug | Reset this process) and the debugee will restart. You don't have to use "Terminate Process" to kill the debugee.

OWL Tips

Overriding Default Exception Behaviour In OWL
When an exception gets thrown in OWL, it gets caught in the main message loop. The default processing, which is defined in TModule::Error() is to notify the user, displaying the message from an xmsg derived exception, offering the user a chance to quit or continue. By overriding TModule::Error in your application, you can display your own message or force close down by returning false as a result. However, it is best to handle exceptions locally in the message they have occurred and only use Error as a last resort.

Running only a Single Instance under Win32
This technique for preventing multiple instances of a program uses a mutex which are truely global under Win32. Win32 cleans up mutexes when an app ends, so this technique is safe, even after your app crashes.

int OwlMain(int, char*[])
{
  TMutex m("UniqueApplicationNameWhichMustNotClashWithAnythingElse");
  if (GetLastError() == ERROR_ALREADY_EXISTS) {
    // Optionally use FindWindow technique to bring
    // existing window to top

  }
  else return MyApp.Run();
}

Dockable Toolbars - Somewhere to Call Home
You may have a toolbar that you set up but do not immediately display. When used this way dockable toolbars should always be created with the THarbor as parent, even if not required initially. You need to use Create() if dynamically added after InitMainWindow().

Dockable Toolbars - Getting Location
You can find out where your TDockableControlBar is on the screen (for example for storing when hiding for reshowing later) by using:

TAbsLocation tbLoc;
TEdgeSlip *edgeSlip = dynamic_cast<TEdgeSlip *>(tb->Parent);
if (edgeSlip) tbLoc = edgeSlip->GetLocation()
else tbLoc = alNone;

You can find out where a floating docakble toolbar is like this:

if (tbLoc == alNone) {
   TRect rect;
   TFloatingSlip* fs = dynamic_cast<TFloatingSlip*>(previousSlip);
   if (fs) {    // Could be just nowhere in the harbor
      fs->GetRect(rect);
      where = rect.TopLeft();
   }
}

(alNone means it is a floating slip or nowhere).

TNoteTab - A Better Tab Control
The TTabControl based on the common control only seems to allow tabs across the top of the screen. By using the TNoteTab you can get a notebook control that functions and looks like the tab used in the IDE message window. It is not limited to 32 bit either.


The TUIMetric Class (Undocumented)
This undocumented class 'encapsulates' the system metrics information you would normally obtain via the API function GetSystemMetrics(). The class consists only of several static members. For example, to get the width of the screen (in pixels) you would use:

int sWidth = TUIMetric::CxScreen;

The TSystem Class (Undocumented)
This is a very useful class for finding out about the system you are running on. It isn't documented but OWL uses it, and you'll find the headers in \bc5\include\winsys\system.h and the body in \bc5\source\classlib\system.cpp. Usage:

if (TSystem::IsWin95())
   // Do some Win95 specific thing

The TCmdLine Class (Undocumented)
You can easily process command lines passed to your app with TCmdLine. This simple helper class is not documented, but the header file in \bc5\include\classlib\cmdline.h explains it all. Here is a code sample from AppExpert (note the string comparison):

TCmdLine cmd(CmdLine);
while (cmd.Kind != TCmdLine::Done) {
  if (cmd.Kind == TCmdLine::Option) {
    if (strnicmp(cmd.Token, "unregister", cmd.TokenLen) == 0) {       UnRegisterInfo();
      return;
    }
  }
  cmd.NextToken();
}

Defining Subkeys with TRegKey
When defining subkeys with TRegKey, do not use a leading "\". This will work under Win95, but will fail under WinNT 3.51, e.g.

TRegKey key(TRegKey::CurrentUser,
  "\\Software\\Honor Oak Systems\\RegisterApp"); // fails
TRegKey key(TRegKey::CurrentUser,
  "Software\\Honor Oak Systems\\RegisterApp"); // Succeeds

Getting the text from an item in a TTreeWindow
In order to get the text from a TTreeWindow item you need to use both a TTreeNode and a TTreeItem. Still, once you've taken those steps just creating a TTreeItem with the default constructor and then using TTreeItem::GetText() will not work. You need to use the TTreeItem::TTreeItem(const char far*, int len = 0) form of the constructor. The following code illustrates:

TTreeNode node(*tree, hItem);
char buff[50];
TTreeItem item(buff, sizeof(buff));
node.GetItem(&item);
// 'buff' now contains the item text
MessageBox(buff, "Text in the item");

TModuleProc Templates Replace LoadLibrary()/GetProcAddress()
TModuleProc<> templates are an excellent way of replacing LoadLibrary()/GetProcAddress() code sequences. Use them to create type safe function calls into dynamically loaded DLLs. e.g.

class MyModule : public TModule {
  MyModule(const char* name, bool shouldLoad, bool mustLoad)
    : TModule(name, shouldLoad, mustLoad) ,
    SomeFunction("SomeFunctionNameInTheDLL") // Initialise proc
    {}
  TModuleProc2<bool, const char*, long> SomeFunction;
};

// Load the lib using new TModule constructor
try {
  MyModule lib("MYLIB.DLL",true,true);
  if (lib.SomeFunction("String",0L)) // Do something
}
catch (TXOwl& x) {
  MessageBox(x.why().c_str(),"Failed to load DLL or Find Proc Error");
}

Grab Notification Messages at the Control
You can handle notification messages sent as WM_NOTIFY (e.g. those sent by the common controls) at the child control by using the same event handling macros as the parent would use. Instead of putting the control id in the macro, use UINT_MAX as the control id, e.g.

EV_LVN_COLUMNCLICK(UINT_MAX, LvnColumnClick),

Easy Speed Menus
You can have context menus automatically handled for you by using the TWindow function AssignContextMenu(TPopupMenu*) to set a menu for any window.

Under 16 bit Windows you can get this functionality by adding:

// Untested code follows
#if defined (BI_PLAT_WIN16)
  void MyWindow::EvRButtonUp(uint modKeys, TPoint& point)
  {
    ClientToScreen(point);     
    SendMessage(WM_CONTEXTMENU,GetHandle(),
      MAKELPARAM((WORD)point.x,(WORD)point.y));
  }
#endif

Classlib

Persistent Streams and seekg()/seekp()
Don't try and reposition in a persistant stream with seekg/seekp. These clear the object database, leading to peculiar mismatches on streamed objects. If you need to reposition during object reading code, use

is.rdbuf()->seekoff( size, ios::cur, ios::in );

which gets the stream buffer and accesses the seeking without disturbing the object database.


Copyright 2000, Reisdorph Publishing. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Reisdorph Publishing is prohibited. All other product names and logos are trademarks or registered trademarks of their respective owners.