Inicio Contáctenos Qué es DatoSoft Descargas


Datos y Software - Soluciones

DatoSoft


Datos y Software - Soluciones

Ir a otros temas...
Programación con C++ Builder

Esta herramienta de programación es la elegida por muchos desarrolladores en lenguaje C++ por su facilidad para crear aplicaciones Windows, casi de una manera tan fácil como en Visual Basic.
Algunos apuntes del día a día...

CONTENIDO


formas que automaticamente se crean
objetos dinamicos
incremental linker se queda pegado
Placing datasets (and data sources) directly on forms
Cadenas en C++ Builder:
filtros
Recorrer los controles de una forma
DBGrids
Variants
Busquedas
Sobre los colores
Para asignarle eventos a TApplication
Paso de parámetros puntero como de salida
Formas con métodos similares
Texto de una listBox
Para que en una combo box no se pueda escribir:
Operador incremento en campos de tablas
Linker failed to create map file error code 0
Para detectar teclas en Windows
Para enviar una tecla a un edit, de modo que el curso se mueva al final.
Para definir eventos dinamicos
detectar que esta corriendo otra instancia
Para crear accesos directos en el menú del botón inicio
Para busquedas:
Para detener una instruccion for, while etc.
Retornar un TDateTime en una función
Posicionando el cursor en TMemo
Fechas y horas Uso de los manipulators si no se usa "using namespace std"
El método length de las std:string cuenta inclusive el null
Para extraer los parametros de la línea de comandos
Detectar dos instancias ejecutandose de una misma aplicación
Constructor hides a otro
Para que los hints duren mas
Como colocar una fecha con el formato correcto del sistema



Formas que automáticamente se crean (en las opciones del proyecto)
Ojo con las formas que automáticamente se crean, porque estando así definidas en las propiedades del proyecto, pues sin querer pueden abrir tablas etc.
Un proyecto en zeos no se debe conectar en tiempo de diseño, porque si luego no esta disponible el servidor, bloquea al C Builder.


Trabajar con objetos dinámicos tiene una ventaja cuando no se desea que el constructor sea invocado en el punto h al declarar la variable, ejemplo:
TPermisos Permisos vs TPermisos *Permisos

Si el incremental linker se queda pegado, revisar en opciones del proyecto, las rutas de los directorios de las lib y los nclude. Quitar la de c:\ si aparece

Note: Placing datasets (and data sources) directly on forms is recommended only for very simple database applications. Even for moderately simple database applications that only work with a few tables or queries on a few forms, using a DATA MODULE eases development and maintenance.

Cadenas en C++ Builder:
1. Están las tradicionales del c: char Cadena[20];
2. La clase standar del C++: string;
3. Las nuevas cadenas largas del Pascal: AnsiString que se redefine como typedef AnsiString String en sysdefs.h. Son las que se utilizan en todos los componentes visuales de la vcl. AnsiString es una clase que soporta el operador + para concatenar.
4. Para arreglos, TStringList, en vcl\classes.hpp
5. Las wchar para manejar UNICODE
Para colocar una cadena que en medio tenga un carácter como \x14 (20 decimal):
Lista->Add("5011 187018E41401003\x14""5012 187203");
Ocurrió en depurar.cpp de signal.

Filtros
Para colocar filtros que dependan de edits, combobox etc.:

        String Filtro; // AnsiString (Clase emuladora string tipo pascal)
    Filtro="IGondola="+CBGondolas->Text; // Construimos la expresión
    TblKarMaest->Filtered= true;
    TblKarMaest->Filter=Filtro;
    TblKarMaest->RecordCount!=0 // Solo cuenta los del filtro!!

Para colocar filtros a campos fecha:
[FFactura]>'01/01/2001'
Otro ejemplo:
Filtro="IFactAgua<>NULL and [FFactura]>'"+FechaDesde->DateString()+"'";
Con FechaDesde del tipo TDateTime

Para colocar expresiones caracter entre comillas:
Filter=String("IGrado=")+IGrado+" and "+IGrupo='"+IGrupo+"'";

Para distinguir de campos vacios
IFactAgua<>NULL

Para recorrer los controles de una forma:

void TfrmNuevoArt::InitDatos() {
        int i;
        TControl *Control= dynamic_cast <TControl *>(this);
    // Recorrer los controles de la forma
    for(i=0; i < Control->ComponentCount; i++) {
        //ShowMessage(Control->Components[i]->Name);
        if (Control->Components[i]->Name.SubString(1,2)=="ed%quot;)
                dynamic_cast <TEdit *>(Control->Components[i])->Text="";
        }
}
    


DBGrids
Un DBGrid es una simple ventana cuyas celdas se dibujan, la celda no es un TControl ni nada por el estilo, ver los ejemplos pruebas\dbgrid) y se vé que para dibujar simplemente se usa el canvas del grid.
Seguramente que al momento de escribir se crea un edit para capturarlo unicamente.

Para colocarle la flechita abajo o el boton con ... en una columna toca con el editor de columnas añadir la del caso y ya sea colocarle
en la propiedad picklist las que deseamos que aparezcan o en el butonstyle colocar ellipse y definir un evento tal (estando ahi
pulsar la ayuda).

El evento que responde a cambio de fila o de record es el ondatachange de un datasource, con Field igual a NULL.
Ver Contador para un ejemplo de como actualizaLabels a medida que se mueven por el grid.

Ejemplo para que la tecla Ctrl-suprimir no funcione en un Grid

void __fastcall TFrmConsFacturacion::DBGrid1KeyDown(TObject *Sender,WORD&Key,
    TShiftState Shift){
if (Key==VK_DELETE && Shift.Contains(ssCtrl))
Key=NULL; // Como es por referencia, se cambia y el evento
// default la recibe como null
}

Para no permitir que la flecha hacia abajo añada registros:
void __fastcall TFrmMateriasPeriodo::DBGrid1KeyDown(TObject *Sender,
    WORD &Key, TShiftState Shift)  {
    (Key==VK_DOWN &&
    DBGrid1->DataSource->DataSet->RecNo==
        DBGrid1->DataSource->DataSet->RecordCount)
    Key= NULL;
}

Otra manera para cuando el Recno no coincida con las lineas del grid, tomando previamente el RecNo del ultimo registro del grid:

void __fastcall TFrmGrabarNotas::DBGrid1KeyDown(TObject *Sender, WORD&Key,
    TShiftState Shift)   {
// Para desactivar Ctrl-Suprimir en el grid.
if (Key==VK_DELETE && Shift.Contains(ssCtrl))
Key=NULL;
else if (Key==VK_DOWN && Query1->RecNo==LastRecord)
Key= NULL;
}


Para poder tener campos de diferentes tablas en un mismo dbgrid, debe colocarse asociado al grid una TTable con características muy especiales:
Primero debe ser un campo añadido con fields editor (boton derecho en ttable) usando new field y no add fields

keyFields= IUsuario (Contenido en table1 a buscar en la otra)
LookUpDataSet=Table2 (Tiene a IUsuario y a NUsuario, con llave IUsuario)
LookKeyFields=IUsuario (Campo a buscar en la tabla 2 que case con
keyfield)
LookUpResultField=NUsuario (Campo a devolver de la tabla 2)
LookUp=True

No se requiere colocar propiedades de lookup en la tabla, ni se requiere indexado, pero con éste funciona mas rápido

Estos campos solo son de lectura y deben definirse en el evento
OnCalcFields.
Si se quiere que aparezca el valor tomado de otra tabla debe ser un lookup, que tambien queda de solo lectura.
Si se quiere mostrar un valor en el campo, pero que no sea calculado ni lookup,de modo que se pueda cambiar, debe colocarse un evento en el DBGrid en OnColEnter, que asigne al campo el valor de la otra tabla, (no se puede en el OnCalcFields porque se produce StackOverFlow), tal como ocurre en kardex,
ej:

if (DbGridFact->SelectedField->FieldName=="ENTRADAS") {
    if (DataModule1->Art->Locate("CodiArti",
                DataModule1->MovTemp->FieldByName("CodiArti")->AsString, TLocateOptions())) {
        DataModule1->MovTemp->Edit();
        DataModule1->MovTemp->FieldValues["Valor"]
                        =DataModule1->Art->FieldValues["ValoComp"];
    }
}
Para chequear la columna actual:
ColumnaActual=DBGrid1->SelectedIndex;

Para darle el foco a una columna dada:
DBGrid1->SelectedIndex=3;
DBGrid1->SetFocus();

Si se quieren los titulos etc.:
if(DBGrid1->Columns->Items[DBGrid1->SelectedIndex]->Title- >Caption=="PrVenta")
Para poner una columna read only:
DBGrid1->Columns->Items[0]->ReadOnly= true;

Para validar a la salida de una celda:
En el OnColExit Colocar el codigo validador, y si es falso,
en el colenter colocar el SelectedIndex en donde estaba. Ver el código fuente del programa de contabilidad, al capturar el asiento.
En un DBGrid para que el texto que escriban este en mayusculas toca definirlo en el On DrawColumnCell asi:

String Texto= DataModule1->MovTemp->FieldByName("CodiArti")->AsString;
if (DataCol==1) { // la columna de interes
DbFact->Canvas->TextOut(Rect.Left+2,Rect.Top+2,Texto.UpperCase());
}
else
DbFact->DefaultDrawColumnCell(Rect, DataCol, Column, State);

Pero para que esto realmente se tome el dato entrado en la tabla toca en el evento OnColEnter del grid, colocar:
CodiArti=DataModule1->MovTemp->FieldByName("CodiArti")->AsString;
DataModule1->MovTemp->FieldValues["CodiArti"]=CodiArti.UpperCase();

La clave para que no se mueva el grid en las validaciones y en los for recorriendo la tabla, es desconectar el grid del datasource en los procesos y justo antes de que se vuelva a visualizar volverlo a conectar.
Una manera de hacerlo es con DataSet->DisableControls, por ejemplo si el
dataset es un Query1: (Ver agua Reporte para lecturas)
Query1->DisableControls();
FrmRptLeerLectura->QuickReport1->Preview();
Query1->EnableControls();

Técnica para hacer que la fila del DBGrid se ilumine en la medida que nos movemos, pero con edicion y todo: (Grabarnotasgrupo en colegios)

En el datasource, evento datachange:
void __fastcall TFrmGrabarNotasGrupo::Datasource1DataChange(TObject *Sender,
TField *Field)
{
RecNum=DSNotasTemp->DataSet->RecNo;
}

En el ondrawColumnCell del dbgrid:

void __fastcall TFrmGrabarNotasGrupo::DBGNotasDrawColumnCell(
    TObject *Sender, const TRect &Rect, int DataCol, TColumn *Column,
    TGridDrawState State)
{
    //La propiedad DefaultDrawing del grid=false en tiempo de diseño.
    //Nosotros le dibujamos el texto
    try {
    if (DM->TblNotasTemp->RecNo==RecNum)
    DBGNotas->Canvas->Brush->Color=clInfoBk;
    DBGNotas->DefaultDrawColumnCell(Rect, DataCol, Column, State);
    }
    catch (MyException &e) {
    ShowMessage(e.Mensaje());
    }
}

Ejemplo de código para validar una columna en un dbgrid. Se hace en el evento updateData del datasource, y si no cumple con la especificación se tira una exception. (tomado de main.cpp en colegios)

void __fastcall TFrmMain::DSEstudiantesUpdateData(TObject *Sender)  {
    try {
    String situacion;
        situacion=DM->TblEstudiantes->FieldByName("Situacion")->AsString;
    if (situacion.IsEmpty())
    return;
    if (islower(situacion[1])) {
    DM->TblEstudiantes->Edit();
    DM->TblEstudiantes->FieldValues["Situacion"]=situacion.UpperCase();
    situacion=situacion.UpperCase();
    }
    if (situacion!="" && situacion!="C" && situacion!="D" &&  situacion!="M") {
            DM->TblEstudiantes->Edit();
        DM->TblEstudiantes->FieldValues["Situacion"]="";
            throw MyException("La situación debe ser solamente C o D o M
                 (Cancelado  Desertor o Matriculado");
    }
    }
    catch (Exception &exception)
    {
    Application->ShowException(&exception);
    }
    catch (MyException &e) {
    Application->MessageBox(e.Mensaje(),"Error",MB_OK|MB_ICONHAND);
    }
    catch (...)
    {
    ShowMessage( String("An exception of type ") + __ThrowExceptionName()
    + "\nwas thrown by line " + AnsiString(__ThrowLineNumber())
    + "\nof file " + __ThrowFileName() );
    }
}


Variants:
Para convertir un variant que contenga un int a una cadena AnsiString simplemente crear la instancia String(variante). Ej:

String(DataModule1->TblKarMaest->FieldByName("IGondola")->Value);


Para busquedas:
DataModule1->TblGondolas->SetKey(); DataModule1->TblGondolas->Fields[0]->AsString = IGondola; if (!DataModule1->TblGondolas->GotoKey()) // Buscar en carga académica la materia y obtener el código del docente DataModule1->TblCargaAcad->SetKey(); DataModule1->TblCargaAcad->Fields[1]->AsString = "INF95"; DataModule1->TblCargaAcad->IndexName="Materia"; if (DataModule1->TblCargaAcad->GotoKey()) IDocente= DataModule1->TblCargaAcad->FieldByName("IDocente")->Value; else ShowMessage("NO Encontrado");
Con locate: bool LocateSuccess; TLocateOptions SearchOptions;SearchOptions << loPartialKey; // Opcional LocateSuccess = CustTable->Locate("Company", "Professional Divers, Ltd.", SearchOptions); // campo contenido }

Sobre los colores
Caso:
Se tiene una forma con color clSilver (TColor)(12632256)o C0C0C0 que es el mismo de BtnFace y se tiene un bitmap que se le oloca ese fondo con los graficadores. Pero al unirlos no resultan igual y se nota la sombra.
Solución cambiar de color de alta intensidad (16 bits) en el modo de vido al modo verdadero (24 bits). Ahi si coinciden. Expliquelo Vargas.
*/


/*
Para asignarle eventos a TApplication
ver en src\cbuilder\pruebas o ConsFacturacion en agua

En el constructor;
DataModule1->TblAbaBancos->BeforeDelete=TFrmBancos::NoDelete;

En el desctructor
DataModule1->TblAbaBancos->BeforeDelete=NULL;

En la implementación del metodo a llamar, en este caso para que no borre.
void __fastcall TFrmBancos::NoDelete(TDataSet *) {
Abort();
}

*/


/*
Paso de parámetros puntero como de salida: (Se cambia la dirección del puntero en la función y sale cambiada.)
Ver ejemplo punt_in_out.cpp en carpeta universidad nacional Ilustra como a semejanza de los enteros etc. que si se desean pasar
como parámetro de salida, se debe pasar su dirección, a los punteros les ocurre lo mismo.

bool buscar(int cod, struct biblioteca **anodo /*direccion de la
variable puntero*/) {
bool Resultado= false;

temp=lst;
while(temp->sgte!=NULL) {
if (temp->codigo==cod) {
Resultado=true;
*anodo= temp; // El contenido de Anodo es cambiado
break;
}
temp=temp->sgte;
}
// Estamos en el ultimo nodo
if(temp->codigo==cod) {
Resultado= true;
*anodo=temp;
}
return Resultado;
}
*/


Formas con métodos similares
Como aprovechar un metodo de una forma en otra que tambien tiene un metodo similar solo con algunas diferencias sin heredar?
Si se maneja friend se puede acceder al metodo de la amiga pero en el metodo la forma se refiere a sus propios edits y demas y no a la que lo llama.
/


Texto de una listBox
Para sacar el texto de una ListBox (es un AnsiString):
ListBox1->Items->Strings[ListBox1->ItemIndex];

Para que en una combo box no se pueda escribir:
usar estilo csDropDownList

Operador incremento con campos de tablas
No se pueden hacer operaciones como esta:
table1->FieldValues["campo1"]+=8;
Toca sacar primero el valor del campo a una variable y luego
table1->FieldValues["campo1"]=variable+8;



Linker failed to create map file error code 0

FAQ913C.txt Linker failed to create map file error code 0
Category :Linker
Platform :All
Product :C++Builder 1.x

Question:
I am getting a "fatal linker error: linker failed to create map file : error code 0." when running an example project.

What do I do to make this error go away?

Answer:

(1) Delete the *.il? in the project
(2) Delete the *.csm files in the lib directory
(3) Delete the deflink.il? files in the bin directory

Para volver a crearlos: bcb -deflink



Para detectar teclas en Windows con C++ Builder
void __fastcall TFrmMain::FormKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
// Las teclas estan definidas en: Virtual-Key Codes
// Aqui se cheque que pulsen F5 y Ctrl y Shift al mismo tiempo:
if (Key==VK_F5 && Shift.Contains(ssCtrl) && Shift.Contains(ssShift))
sndPlaySound("copyright.wav", SND_SYNC);


Para enviar una tecla a un edit, de modo que el curso se mueva al final.
PostMessage(EdICuenta->Handle, WM_KEYDOWN,VK_END,0);

Para definir eventos dinamicamente, solo para una forma:

// Definir eventos dinamicamente que nazcan y mueran en esta forma:
DataModule1->DSFacturas- >OnDataChange=TFrmConsFacturacion::FacturasDataChange;
DataModule1->TblFacturas- >AfterPost=TFrmConsFacturacion::FacturasAfterPost;
DataModule1->TblFacturas- >BeforePost=TFrmConsFacturacion::FacturasBeforePost;

Luego en el destructor:
// Quitar los eventos definidos al empezar
DataModule1->DSFacturas->OnDataChange=NULL;
DataModule1->TblFacturas->AfterPost=NULL;
DataModule1->TblFacturas->BeforePost=NULL;

Ver Agua ConsFacturacion


Ejemplo para detectar que esta corriendo otra instancia de un
programa en WIN32:
try
{
CreateMutex(NULL, false, Application->ExeName.c_str());
if (ERROR_ALREADY_EXISTS==GetLastError()) {
ShowMessage("Ya se está ejecutando el programa. Observe en la
barra
de tareas.");
PostQuitMessage(0);
}
else {
Application->Initialize();
Application->CreateForm(__classid(TDataModule1), &DataModule1);
Application->CreateForm(__classid(TFrmMain), &FrmMain);
Application->Run();
}
}
*/

/*
Para crear accesos directos en el menú del botón inicio,
Aún se sigue utilizando DDE para conversar con el Program Manager.
La VCL tiene un componente que encapsula el inicio y final de la conversación: TDdeClientConv
Basta colocarle en las propiedades, DdeService y DdeTopic, "program" en cada uno, y luego DdeClientConv1- >ExecuteMacro("[CreateGroup(tigre2)][AddItem(e:\\ut\\fconvert.exe,ivan)
]",
false))
Ve en Pruebas, PrDde
*/


/*
Para detener una instruccion for, while etc.
Para permitir que un botón Cancelar actúe y detenga un ciclo, debe colocarse dentro del ciclo: Application->ProcessMessages();
Y El código asociado al botón debe ser colocar una variable a false, variable que debe ser una de las condiciones del ciclo, por supuesto.
No funciona colocar PostQuitMessage() o Close() en el código asociado al click del boton, porque regresa al ciclo y continúa dando vueltas.


Retornar un TDateTime en una función
Si una funcion necesita retornar un TDateTime debe ser así, pues usando FieldByName sale Error de generacion de codigo en CBuilder 1.0:
TDateTime TUsuario::GetFechaPago() {
return DataModule1->TblUsuarios->FieldValues["FPagoAnt"];
}


Posicionando el cursor en TMemo
Para posicionarse al inicio de un TMemo
Memo1->SelStart=0;
Memo1->SelLength = 0;
Memo1->Perform(EM_SCROLLCARET, 0, 0);
Memo1->SetFocus();

Para ubicarse en cierto punto y seleccionando texto: (didactica.exe)
Memo1->SetFocus();
Memo1->SelStart=1416;
Memo1->SelLength = 10;

Fechas y horas
Ejemplo de resta dados dos fechas y dos horas, mostrando la diferencia en horas (tanto la resta de fecha como de horas debe multiplicarse por 24)


TDateTime FechaAct, HoraAct,FechaReg, HoraReg;
int DifHoras;

FechaAct=TDateTime().CurrentDate();
HoraAct=TDateTime().CurrentTime();
FechaReg=TDateTime().CurrentDate()-2;
HoraReg=TDateTime().CurrentTime()+6./24;
DifHoras=(int)(FechaAct-FechaReg)*24+(double)(HoraAct-HoraReg)*24;
ShowMessage(DifHoras);*/

Mas sencillo así:
TDateTime().CurrentTime().DecodeTime(&ha, &ma, &sa, &msa);
Config.GetHoraTest().DecodeTime(&ht, &mt, &st, &mst);
if (ha==ht && ma==mt && abs(sa-st)<=15) {

ç
// Funcion del API para mostrar el formato de fecha del sistema
::GetLocaleInfo(
LOCALE_SYSTEM_DEFAULT,
LOCALE_SSHORTDATE, // locale identifier
BufDate, // address of buffer for information
100 // size of buffer
);
Label2->Caption=String("Fecha de inventarios iniciales: (")+BufDate+")";
imprime ("mm/dd/yyyy")


Si se quiere trabajar con campos time como llave, debe grabarse con cero milisegundos para que cuando se vaya a buscar haya coincidencia.
Recordar que es un doble y de lo contrario no coinciden lo que se grabo con lo que se escribe en el sql. Ejemplo de signal, primero
decodificamos la hora:
HoraSignal.DecodeTime(&Hora, &Min, &Sec, &MilSec);
Y al grabarla la ponemos con cero milisegundos
FrmDMSignal->TblHistoria- >FieldValues["THora"]=TDateTime(Hora,Min,Sec,0);

Luego en la manipulacion de la tabla:
THora=FrmDMMonitor->TblCola->FieldByName("THora")->AsDateTime;
os<<"update historia set TNotas=\""<<Memo1->Text.c_str()<<"\",
IMonitor=\""<<Login.c_str()
<<"\" where dfecha=\""<<MesDiaAnio(LblFecha->Caption).c_str()
<<"\" and THora=\""<<THora.c_str()<<"\" and Event=\""
<<Evento.c_str()<<"\""<<ends;


P ara utilizar la hora en SQL toca utilizar el formato militar pues el a.m. de la cadena no lo acepta. Para no cambiar el formato de hora del sistema operativo se debe usar el método FormatString() así:

String HoraActual=TDateTime().CurrentTime().FormatString("hh:mm:ss")
Que nos retorna la hora en formato militar: Ej: 14:15:08

Ejemplo que muestra como seleccionar eventos que ocurrieron 24 horas antes:
select icuenta,event from historia where ("06/25/2003"-dfecha)<=1 and "06/25/2003">dfecha and (thora-"08:15:30")*24<=24 and icuenta=6837

os<<"select ICuenta, Event from historia " <<"where (\""<<aFecha.FormatString("mm/dd/yyyy").c_str()<<"\"-dfecha)<=1 and
(\"" <<aFecha.FormatString("mm/dd/yyyy").c_str()<<"\">=dfecha) and (thora-\""<< HoraActual.c_str()<<"\")*24<=24 and icuenta="<<aICuenta<<ends;


Uso de los manipulators si no se usa "using namespace std"

#include<iomanip>
#include <sstream>

void __fastcall TForm1::Button1Click(TObject *Sender)
{
std::ostringstream os;
char b[255];

os<<"1012 "<<std::setfill(' ')<<std::setw(4)<<89<<" 00"<<std::ends;
ShowMessage(os.str().c_str());
ShowMessage(itoa( os.str().length(),b,10) );

}



El método length de las std:string cuenta inclusive el null!
std::ostringstream os;
char b[255];

os<<"01234567890123456789"<<std::ends;
ShowMessage(os.str().c_str());
ShowMessage(itoa( os.str().length(),b,10) ); // imprime 21





Para extraer los parametros de la línea de comandos (SAB)
//LPTSTR GetCommandLine(VOID) para hacerlo con el API de windows
// Con las variables globales del IDE (#include DOS)
if (_argc==2 && strchr(strupr(_argv[1]),'C'))
else if (_argc==2 && strchr(strupr(_argv[1]),'U'))



Para evitar warnings de que tal constructor hidden tal otro, y que de ahi para adelante en la herencia ya no se verá el base etc.
Crear otro constructor, que en C++ se puede, y a ese añadirle el parámetro que necesitemos, que el compilador llamará al que se
necesite según tenga o no parámetro.
Ver src\cbuilder\repositorio\repair.cpp y h.
__fastcall TRepairDialog(TComponent* Owner);
__fastcall TRepairDialog(TComponent* Owner, String aRuta);


Para cambiar las propiedades de los hint con el fin de mostrar mensajes con mas duracion etc:
En el constructor o similar:
Application->OnShowHint=DoShowHint;

Y luego:

void __fastcall TfrmCategoria::DoShowHint(System::AnsiString &HintStr, bool &CanShow,
THintInfo &HintInfo)
{
DBGrid1->Hint="Hola";
HintInfo.HintColor = clAqua;// Changes only for this hint
HintInfo.HintMaxWidth = 120; // Hint text word wraps if width is greater than 120
//HintInfo.HintPos.x += SpeedButton3->Width; // Move hint to right edge
HintInfo.HideTimeout=10000; // Poner a 10 segundos la mostrada del hint
}

Detectar dos instancias ejecutandose de una misma aplicación
Para evitar que haya dos instancias de una misma aplicación corriendo:
CreateMutex(NULL, false, GetExeName.c_str()); //GetExeName está en clUtil
// solo es correcto el nombre sin la extensión y sin path
if (ERROR_ALREADY_EXISTS==GetLastError()) {
ShowMessage("Ya se está ejecutando el programa. Observe en la barra de tareas.");
PostQuitMessage(0);
}
// Una forma general de manejar exceptions de todo tipo:
try
{
Application->Initialize();
Application->CreateForm(__classid(TDM), &DM);
Application->CreateForm(__classid(TFrmMain), &FrmMain);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
catch (MyException &e) {
Application->MessageBox(e.Mensaje(),"Error",MB_OK|MB_ICONHAND);
}
catch (...)
{
// Por aca entran las C++ Exception.
//WriteToFile("falla.txt", (String( itoa(i,Temp,10))+"\n").c_str());
ShowMessage( String("An exception of type ") + __ThrowExceptionName()
+ "\nwas thrown by line " + AnsiString(__ThrowLineNumber())
+ "\nof file " + __ThrowFileName() );

}

return 0;
}

Como colocar una fecha en un control, con el formato del fecha del sistema:
char BufDate[20];
// Funcion del API para mostrar el formato de fecha del sistema, ej: mm/dd/yyyy
::GetLocaleInfo(LOCALE_SYSTEM_DEFAULT,LOCALE_SSHORTDATE, BufDate,);
TDateTime fTemp(GetAnioActual(), 12,31);
edFechaVenc->Text=fTemp.FormatString(BufDate);