How to dynamically call a form in C++ Builder XE3? - c++builder

I'm building an application in which Im populating menus using DB. I can create menu items but im having trouble linking "On Click" event to particular forms. I have stored names of the forms classes in my DB and trying to use RTTI to bind them at runtime. Following is the snippet of my code that Im trying to run.
__fastcall TfrmMainMDI::TfrmMainMDI(TComponent *Owner)
: TForm(Owner)
{
// Register 2 form classes
RegisterClass(__classid(TfrmSecurity));
RegisterClass(__classid(TfrmPassword));
}
Now when I try to run following code to call the form it gives "Access violation" error.
TForm *frm = (TForm*)TFormClass(FindClass(formName));
UnicodeString str = frm->Name;
frm->Show();

Do this:
TForm *frm = 0;
Application->CreateForm( TFormClass(FindClass(formName)), &frm );
Then if frm is not null,
frm->Show();

TForm *frm = new TForm(this);
if( frm != NULL )
{
frm->ShowModal();
//or
frm->Show();
}

Related

TClientDataSet OnNewRecord vs. AfterInsert

My question is about inserting records into a table on a firebird database. The table is very simple - it has only 2 columns:
CREATE TABLE myTable
(
COL_ID CHAR(36) NOT NULL CONSTRAINT PK_COL_ID PRIMARY KEY USING INDEX IX_COL_ID,
COL_ACRONYM VARCHAR(255)
);
In my application (c++ Builder XE10) I have the following constellation:
A TDataSource connected to
A TClientDataSet connected to
A TDataSetProvider connected to
A TFDTable connected to
A TFDConnection connected to
A Firebird Database
The application does the following:
Insert a new row using TClientDataSet.Append();
Edit the newly inserted record.
Save this record using TClientDataSet.ApplyUpdates(-1);
Everything is working as expected as long as I do the 2nd step manually or by editing the data within the AfterInsert event:
__fastcall TFormMain::TFormMain(TComponent* Owner)
: TForm(Owner)
{
ClientDataSet1->Active = true;
}
UnicodeString TFormMain::GenerateGuid( void )
{
// ...some fancy code creating and returning a GUID...
}
void __fastcall TFormMain::ButtonAppendClick(TObject *Sender)
{
ClientDataSet1->Append();
}
void __fastcall TFormMain::ButtonSaveClick(TObject *Sender)
{
ClientDataSet1->ApplyUpdates(-1);
}
void __fastcall TFormMain::ClientDataSet1AfterInsert(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Whatever: this works!";
}
This works good... so far...
Due to some other changes I decided to move the the auto-creation of data into the OnNewRecord event of the TClientDataSet:
void __fastcall TFormMain::ClientDataSet1NewRecord(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Not too good...";
}
For the first moment it looked good, because the DB-controls on the GUI have been filled with the correct data. But as soon as I hit the Save Button the data disappeard and the new record has not been stored to the database - as if I cancelled the process.
Secondly I noticed, that if I change one of the columns MANUALLY before executing ApplyUpdates(),... then the record is stored.
So I simply added the following line for automatic posting:
void __fastcall TFormMain::ClientDataSet1NewRecord(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Not too good...";
DataSet->Post();
}
This minor change did its job.
My question now is: WHY?
Does AfterInsert automatically post the new record?
Are records that were added by Append() automatically cancelled, when they are left unchanged after the OnNewRecord event?
regards and thanx
Herwig
As far as I know, the difference between TDataSet's OnNewRecord and AfterInsert event handlers is:
Editing fields values from the OnNewRecord will NOT flag the record as modified
Editing fields values from the AfterInsert will flag the record as modified
I guess that this is the cause of the problem

Load imagelist from CS .net wrapper into Delphi

I'm writing a CS .net wrapper to be used in a Delphi application and I would like to load images from the "remote" .net lib so I don't need to maintain a "copy" imagelist in Delphi.
Question how do I fetch the imagelist via a TLB?
I think I have 3 options to implement this
on startup of application, fetch imagelist by ref and copy to a local imagelist. This gives me an IUnknown as ref parameter in the TLB, can I use that somehow?
I could use a string/widestring or maybe a stream of some sort, I think that could/would be marshalled as a delphi type.
I could store the imagelist as bitmap and load that in delphi on startup - but who would fancy to do that :)
Any ideas / suggestions a more than welcome.
This is the wrapper method
public bool LoadImageList(ref ImageList imagelist16, ref ImageList imagelist32, ref String ResMsg)
{
ResMsg = "Imagelist could be loaded: ";
try {
imagelist16 = null;
imagelist32 = null;
if (!_initialized) return false;
imagelist16 = VideoOS.Platform.UI.Util.ImageList;
imagelist32 = VideoOS.Platform.UI.Util.ImageList32;
ResMsg = "Images loaded";
return true;
}
catch (Exception e) {
ResMsg = ResMsg + e.Message;
return false;
}
}
This is the Delphi TLB unit
function LoadImageList(var imagelist16: IUnknown; var imagelist32: IUnknown;
var ResMsg: WideString; out pRetVal: WordBool): HResult; stdcall;
"stdole.IPictureDisp" interface as parameter type should do the trick.
COM Interop & image conversion (via API) : http://blogs.msdn.com/b/andreww/archive/2007/07/30/converting-between-ipicturedisp-and-system-drawing-image.aspx

How to cast to TMenuItem in TActions Execute method?

I have a number of related TMenuItems, in a CodeGear C++ VCL application.
Each TMenuItem is associated to the same action (TAction).
When a MenuItem is clicked, the action fires (its execute method that is).
I will need to, somehow, cast the Sender parameter in the actions OnExecute function to figure out which menuitem that was clicked.
Currently I have something like this
void __fastcall TMoleculixDesktopMainUnit::openMoleculeSelectionFormAExecute(TObject *Sender)
{
//User selected a menuitem under Molecules Menu
TAction* anItem = dynamic_cast<TAction*>(Sender);
//AminoAcidsMI is a TMenuItem
if(AminoAcidsMI == dynamic_cast<TMenuItem*>(anItem->Owner))
{
//Open molecule search form with aminoacids
MLog()<<"Looking for Amino Acids..";
}
}
But the above does not work The actions Owner is NOT the MenuItem.
Use the TAction::ActionComponent property, which specifies the component that triggered the action.
void __fastcall TMoleculixDesktopMainUnit::openMoleculeSelectionFormAExecute(TObject *Sender)
{
//User selected a menuitem under Molecules Menu
TAction* anItem = dynamic_cast<TAction*>(Sender);
if (!anItem) return;
AminoAcidsMI == dynamic_cast<TMenuItem*>(anItem->ActionComponent);
if (AminoAcidsMI)
{
//Open molecule search form with aminoacids
MLog()<<"Looking for Amino Acids..";
}
}

breezejs : registerEntityTypeCtor for Added entities only?

I've used the registerEntityTypeCtor function to add some initialization code when an Entity is created. However this code is fired regardless of the state of the Entity (Added vs Changed vs Detached, etc....)
I'd like the initialization code inside registerEntityTypeCtor to only applied to Entity with the state Added. The problem is that the state of the Entity is only set AFTER the bespoke constructor was called. Anything I could do to work around that ?
function configureMetadataStore(metadataStore) {
metadataStore.registerEntityTypeCtor('Mandate', function () {
this.blah = 'test';
}, mandatInitializer);
//Validator.register(someValidator);
logger.info('Validators applied');
}
function mandatInitializer(mandat) {
mandat.TransactionType = '0';
mandat.Status = '0';
mandat.NextSequenceType = '0';
mandat.MandateType = '0';
}
The method registerEntityTypeCtor has three input parameters: the entity name,the constructor, and the initializer method. I think that you can use the third parameter for doing the inizialization only in added entities.
dtContext.metadataStore.registerEntityTypeCtor(entityName, constructor, initializerMethod);
---EDIT---
You can check if the id is unefined in the initializerMethod:
function initializerMethod(entity){
if(entity.id()===unefined || entity.id()=== null){
//Do things that you want with the new entity
//...
//Initilize the id with a temporal value that would be override in the server side.
}
}

Visual Studio 2010 add in - events not triggered

I have written an add in that takes the active document as a parameter. So each time that the active document has changed, I need to know. To do so, I wanted to use "Events.DocumentEvents.DocumentOpened" event of the DTE2 object. But the problem is that event is never get fired even though I change the active document.
The code snippet is as follows
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_applicationObject.Events.DocumentEvents.DocumentOpened += new _dispDocumentEvents_DocumentOpenedEventHandler(DocumentEvents_DocumentOpened);
...
}
void DocumentEvents_DocumentOpened(Document Document)
{
MessageBox.Show("Not called");
}
I have tried with DocumentEvents as well but no success. Any ideas?
I had just realized that I focused on the wrong event and thats why it was not fired. With the code below I got what I intended to. So instead of DocumentEvents, I had to use WindowEvents.
....
_applicationObject.Events.WindowEvents.WindowActivated += new _dispWindowEvents_WindowActivatedEventHandler(WindowEvents_WindowActivated);
}
void WindowEvents_WindowActivated(Window GotFocus, Window LostFocus)
{
if (ucCAST != null && GotFocus.Document != null)
((CAST)ucCAST).refreshCode(GotFocus.Document.Name);
}

Resources