Borland C++ Builder: Form problemen

Pagina: 1
Acties:

  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Voor dat er rtfm termen geroepen worden: ja ik heb gezocht op het Internet, alsmede hier op het forum naar het probleem dat ik ga beschrijven. De oplossingen die ik gevonden heb op het Internet lossen mijn probleem slechts gedeeltelijk op, maar het resultaat is zo vies (en introduceert bovendien een ander ongemak) dat ik het toch ook hier probeer.

Sinds kort gebruiken we op het werk Borland C++ Builder 6 (daarnaast maken we al jaren gebruik van MS VC++). De volgende situatie:

- Ik heb een normale applicatie (GUI, geen console) gemaakt met een aantal dialogs (forms)
- Ik heb een DLL gemaakt met daarin verschillende classes zoals een SQL wrapper en een aantal dialogs (forms).

Tijdens het compileren/linked van de DLL heb ik een import library laten genereren, welke ik in het project van de applicatie heb opgenomen.

Alles werkt in principe prima. De classes in de DLL kan in gebruiken, de dialogen ook. Er is echter één klein detail. Sinds ik de DLL in mijn applicatie gebruik, wordt voor ieder dialog dat ik open (hetzij uit mijn applicatie/DLL/of zelfs common dialogs van Windows) een button op de taakbalk gemaakt. Dit is bijzonder vervelend en ik heb echt geen idee waarom dit gebeurt. Sterker nog, wanneer ik dan een van die buttons aan klik om een ander dialog van mijn applicatie te activeren (dat niet het actieve venster is), dan wordt het 'geactiveerd'. Dit zet ik met opzet tussen '', want het venster wordt wel zichtbaar (op de voorgrond gezet) maar is verder niet te benaderen.

Nu wordt er op de Internet-sites die ik heb bezocht aangeraden om dan je dialogen de style 'WS_EX_TOOLWINDOW' te geven. Maar dit vind ik dus echt niet de bedoeling:

- Dit zul je dan bij ieder dialoog (dus ook die van Windows) moet gaan toepassen. Vies!
- De applicatie komt niet meer voor in de 'ALT-TAB' lijst.

Op de gevonden Internet-sites, beschreef iedereen soortgelijke problemen, maar had niemand een oplossing (behalve dan het aanpassen van de Extended Style van je window).

Dit is echt geen optie. Heeft iemand ooit een soortgelijk probleem gezien/gehad, weet iemand een oplossing?

Ik heb zelf het vermoeden dat het aan de memory manager van Borland ligt die met de DLL meegelinkt wordt (verplicht, anders moet ik de opzet van de functie's aanpassen).

p.s.: Indien ik mijn applicatie geen gebruik meer laat maken van de DLL en alle code uit de DLL gewoon in de applicatie zet, dan werken de dialogen zoals je zou verwachten. Dat wil zeggen: Er komt 1 button op de taakbalk voor de gehele applicatie, ongeacht hoeveel vensters er open staan.

"The fastest code, is the code that is never called."


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Volgens mij krijgt elke window zonder parent een knop op de taakbalk. WS_EX_APPWINDOW windows krijgen sowieso een knop, en WS_EX_TOOLWINDOW krijgen nooit een knop.

Dus als al jouw windows parentless zijn is het logisch dat die knoppen daar komen.
(dit lijkt me overigens meer een win32 probleem dan een borland specifiek probleem)

[ Voor 15% gewijzigd door .oisyn op 18-03-2004 22:24 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Ja daar heb je ook gelijk in, maar dat is dus het vreemde. Alle windows hebben een parent-window. De gehele parent-child structuur van de windows klopt ook verder, ook al doet zich dit voor:
Sterker nog, wanneer ik dan een van die buttons aan klik om een ander dialog van mijn applicatie te activeren (dat niet het actieve venster is), dan wordt het 'geactiveerd'. Dit zet ik met opzet tussen '', want het venster wordt wel zichtbaar (op de voorgrond gezet) maar is verder niet te benaderen.
Maar het is toch vreemd dat zodra ik de DLL in mijn applicatie gebruik, alle dialogen (ook de common dialogs van Windows dus!!) een aparte button op de taakbalk krijgt. Ik doe verder niks vreemds in de DLL.

Anyone?

"The fastest code, is the code that is never called."


  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Ik ben er inmiddels achtergekomen (via Spy++ van MS VC++) dat indien ik de applicatie gebruik laat maken van de DLL, dat er dan geen owner window wordt aangemaakt (type TApplication). Normaal gesproken zouden alle windows van de applicatie dit window als owner moeten hebben.

"The fastest code, is the code that is never called."


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Zoals je zelf al hebt opgemarkt is de oorzaak hiervan dat je window de applicatie niet als parent window krijgt. Waarom is dat? Nou, omdat je nu in elke dll/exe een eigen instantie hebt van TApplication en niet, zoals het hoort, een enkele in je hele applicatie. Om dit en andere dingen goed te laten werken zal je de instanties van TApplication (Application) en TScreen (Screen) gelijk moeten zetten met je exe. Dat kan door bijvoorbeeld een intializatie methode in je dll aan te roepen na het laden die de pointers van de exe naar de dll doorgeeft.

We adore chaos because we like to restore order - M.C. Escher


  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Hmmm. Wat is eigenlijk het idee hierachter? Het is me trouwens wel gelukt om de windows weer op een normale manier te laten functioneren (m.b.t. de taakbalk) door van het Application object (TApplication) de functie CreateHandle aan te roepen. Volgens de help wordt het afgeraden om dit direct te doen, aangezien in de constructor van het Application object deze functie al aangeroepen wordt. Na aanroep van deze functie wordt tevens het owner window van de applicatie ook aangemaakt. Enige nadeel tot dusver is dat de applicatie geen icon meer heeft. Maar ik betwijfel of dit eigenlijk wel een nette oplossing is.

Jou idee om de pointers naar het Application en Screen object vanuit de applicatie door te geven aan de DLL heeft bij mij geen effect gehad. Ik heb dus een initialisatie functie geschreven die aangeroepen wordt na het laden van de DLL. Misschien kun je het een klein beetje meer verduidelijken?

"The fastest code, is the code that is never called."


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Het idee is dat de VCL daar opgebaseerd is. Het omzijlen ervan geeft soms rare effecten, zoals je al gemerkt hebt.

Nee, dat is geen nette oplossing, want nu heb je gewoon echt meerdere TApplications die elkaar alleen maar tegenwerken.

De code zal er ongeveer zo uitzien:
C:
1
2
3
4
5
6
7
8
9
// EXE
  Init(Application, Screen);

// DLL
void Init(TApplication *App, TScreen *AScreen);
{
  Application = App;
  Screen = AScreen;
}

Ik doe normaal Delphi, dus je zal de code misschien nog even moeten aanpassen.

De Memory Manager is er voor zodat je AnsiStrings over kan geven tussen de DLL en de EXE.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Dit is heel simpel op te lossen door je application handle mee te geven aan je DLL en deze handle toe te wijzen aan de Application->Handle in de DLL.

  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Bedankt voor jullie reacties. Ik heb het een en ander even gecontroleerd m.b.t. het doorgeven de Application & Screen object naar de DLL. Nog voor dat ik de Application/Screen objecten in de DLL laat wijzen naar die van de applicatie, heb ik gecontroleerd hoe de objecten geïnitialiseerd zijn. Het viel me in ieder geval op dat de Application/Screen objecten in de applicatie en DLL zich op exact dezelfde adressen bevinden (ook voor de initialisatie). Daarnaast heb ik al jullie geopperde ideeën toegepast, maar het had geen van allen het juiste effect.

Ik twijfel absoluut niet aan jullie kennis. Maar wat er dus niet gebeurd is het volgende:

- De applicatie window wordt niet aangemaakt/geregistreerd (dit heb ik tevens gecontrolleerd m.b.v. Spy++ van MS VC). Dit is ook te zien indien ik de objecten bekijk tijdens runtime.

Indien ik de functie CreateHandle aanroep, wordt de applicatie window wel gecreeërd en geregistreerd.
Nee, dat is geen nette oplossing, want nu heb je gewoon echt meerdere TApplications die elkaar alleen maar tegenwerken.
Dit heb ik nog niet geverifieerd. Dat zal ik ook nog doen.

"The fastest code, is the code that is never called."


Verwijderd

Wie is de parent van je forms? Als je NULL gebruikt dan krijgt deze ook zijn eigen button. Gebruik de Application->CreateForm() (tenzij je dit natuurlijk al geprobeerd hebt).

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Primal schreef op 19 maart 2004 @ 12:09:
Het viel me in ieder geval op dat de Application/Screen objecten in de applicatie en DLL zich op exact dezelfde adressen bevinden (ook voor de initialisatie). Daarnaast heb ik al jullie geopperde ideeën toegepast, maar het had geen van allen het juiste effect.

Ik twijfel absoluut niet aan jullie kennis. Maar wat er dus niet gebeurd is het volgende:

- De applicatie window wordt niet aangemaakt/geregistreerd (dit heb ik tevens gecontrolleerd m.b.v. Spy++ van MS VC). Dit is ook te zien indien ik de objecten bekijk tijdens runtime.
Dan maak je al gebruik van runtime packages en is er dus maar 1 instantie van Application in de vcl70.bpl (of hoe ie ook in BCB heet).

Heb je wel een form in je applicatie (exe)? Je moet er minstens wel 1tje hebben, want anders maakt ie idd geen handle aan. CreateHandle aanroepen forceerd dat, dus dat is in dat geval een oplossing.

[ Voor 6% gewijzigd door LordLarry op 19-03-2004 13:19 ]

We adore chaos because we like to restore order - M.C. Escher


  • Primal
  • Registratie: Augustus 2001
  • Laatst online: 01-05 22:09
Ja de applicatie heeft minstens 1 form, zoals ik had beschreven in mijn startpost (no offense by the way, serious). Ik heb inderdaad nog eens bekeken wat er gebeurt indien ik CreateHandle aan roep, maar het bestaande Application object blijft verder intact. Volgens de help van Borland wordt door die functie ook alleen maar de Windowclass voor de applicatie geregistreerd en wordt de applicatie window aangemaakt. Het wordt wel afgeraden om de functie direct aan te roepen, maar aan de andere kant spreken ze dat ook weer tegen door te zeggen dat "de functie aangeroepen kan worden om de applicatie window aan te maken indien dat (nog) niet gebeurd is" (even in vrije vertaling). Ik vraag me af of dit wel de juiste manier is, maar bij gebrek aan verdere informatie houd ik het hier maar op. Het werkt perfect voor zover ik het kan zien. Bedankt voor jullie hulp.

.edit:

Voor mensen die ooit tegen hetzelfde probleem aanlopen. Het is dus op te lossen door in de WinMain (daar waar ook het Application (instantie van TApplication) wordt geïnitialiseerd) de member functie CreateHandle aan te roepen. Dus:

C++:
1
Application->CreateHandle();


Let wel op dat het icoon dat je, via de projectsettings hebt ingesteld voor je applicatie, na aanroep van deze functie niet meer in je Application object is opgenomen. Dit kun je oplossen in code door het icoon na deze aanroep te laden van resource, kopiëren van een andere form etc. Ik denk dat het het beste is om de memberfunctie CreateHandle aan te roepen voor de aanroep van de memberfunctie Initialise.

Deze kan op slot.

[ Voor 50% gewijzigd door Primal op 19-03-2004 23:38 ]

"The fastest code, is the code that is never called."

Pagina: 1