A
rudpower schrieb:
Du kannst das Problem auf einem der folgenden Wege beheben:
- einen eigenen Dialog von TOpenDialog ableiten, die Execute()-Methode überschreiben und mehr Speicherplatz übergeben (vielleicht ein paar MB). Das verlagert das Problem zwar nur, aber es funktioniert wahrscheinlich für die meisten Fälle.
- C++Builder >= 2007 und Windows >= Vista benutzen. Da gibt es neue Dateidialoge mit gescheitem Interface, das diese Probleme nicht hat, und wenn man es nicht explizit abstellt, benutzen VCL-Anwendungen automatisch die neuen Dialoge
Möglichkeit 2 scheidet bei mir aus da ich mit Windows XP und dem BCB 5 arbeite.
War auch eher der obligatorische Wink mit dem Zaunpfahl. Mit alter Software machst du dir nur das Leben schwer.
rudpower schrieb:
Leider hab ich mit Vererbung bisher nicht gearbeitet bzw. hab es nicht gebraucht.
Aha, du machst Learning by Doing?
Ich rate dir, nimm dir mal die Zeit für ein paar richtige Bücher zum Thema. Es lohnt sich.
rudpower schrieb:
Das müsst ja so ungefähr funktionieren:
class MyTOpenDialog : public TOpenDialog {
};
Kann ich die Klasse in private der Form deklarieren? Wie überschreibe ich die Execute Methode bzw ändere die maximale Größe der Dateinamenmenge?
Zunächst wirst du feststellen, daß TOpenDialog dir die Änderung nicht einfach machen wird (alle Codebeispiele sind aus C++Builder 6, weil ich C++Builder 5 nicht besitze):
// dialogs.pas, l. 643ff
function TOpenDialog.DoExecute(Func: Pointer): Bool;
const
MultiSelectBufferSize = High(Word) - 16; // <-- hier wird die Puffergröße definiert
...
var
TempFilter, TempFilename, TempExt: string;
begin
...
if ofAllowMultiSelect in FOptions then // <-- hier wird die Puffergröße gesetzt
nMaxFile := MultiSelectBufferSize else
nMaxFile := MAX_PATH;
SetLength(TempFilename, nMaxFile + 2); // <-- hier wird der Puffer angelegt
...
end;
// l. 868ff
function TOpenDialog.Execute: Boolean;
begin
Result := DoExecute(@GetOpenFileName);
end;
All das verbirgt sich nicht etwa in einer kleinen, dem spezifischen Zweck der Pufferallokation zugedachten virtuellen Funktion, sondern in der monolithischen, nichtvirtuellen Funktion DoExecute(). TOpenDialog.Execute(), dankenswerterweise überschreibbar, ruft die Funktion in recht einfacher Weise auf. Du wirst also von TOpenDialog ableiten, die Execute()-Funktion überschreiben und die komplette Implementation von DoExecute() wiederholen müssen.
Damit du nicht den schönen Tag damit verbringen mußt, Delphi nach C++ zu übersetzen, entscheidest du sodann, dein Derivat, nennen wir es zweckgemäß TOpenDialogForManyFiles, in Delphi zu implementieren. Du erstellst also in C++Builder ein neues Package, sagen wir "MyFixesForAncientBCB5VCL.bpl", und speicherst es irgendwo. In demselben Ordner erstellst du eine .pas-Datei folgenden Inhalts:
unit OpenDialogForManyFiles;
interface
uses
Types, Dialogs;
type
TOpenDialogForManyFiles = class (TOpenDialog)
private
function DoExecute(Func: Pointer): Bool;
public
function Execute: Boolean; override;
end;
procedure Register;
implementation
uses
SysUtils, Classes, Controls, Forms, CommDlg, Windows;
function TOpenDialogForManyFiles.DoExecute(Func: Pointer): Bool;
const
MultiSelectBufferSize = 1024 * 1024 * 4; // <-- neue Puffergröße: 4 MB
OFN_ENABLESIZING = $00800000; // auch ganz praktisch
// den Rest übernimmst du unverändert aus TOpenDialog.DoExecute() in dialogs.pas!
end;
function TOpenDialogForManyFiles.Execute: Boolean;
begin
Result := DoExecute(@GetSaveFileName);
end;
procedure Register;
begin
RegisterComponents ('Dialoge', [TOpenDialogForManyFiles]);
end;
end.
Die fügst du dann dem Package-Projekt hinzu und kompilierst es. Du wirst einen Haufen Fehlermeldungen bekommen, weil DoExecute() auf diverse private Felddeklarationen von TOpenDialog zugreift ("undefinierter Bezeichner FFiles" oder so). Die Fehler kannst du allesamt umgehen, indem du den "F"-Präfix wegnimmst, so daß deine Funktion auf die korrespondierenden (öffentlichen) Eigenschaften zugreift - mit folgenden Ausnahmen:
diese Zeile:
FCurrentFilterIndex := FFilterIndex;
für FCurrentFilterIndex gibt es keine korrespondierende Eigenschaft; kommentiere die Zeile einfach aus.
das hier:
if (FFlags and OFN_EXTENSIONDIFFERENT) <> 0 then
Include(FOptions, ofExtensionDifferent) else
Exclude(FOptions, ofExtensionDifferent);
if (FFlags and OFN_READONLY) <> 0 then
Include(FOptions, ofReadOnly) else
Exclude(FOptions, ofReadOnly);
Dieser Zugriff ist nur für L-Values gestattet, und das sind Properties nur in Zuweisungen; ändere es ab in
if (Flags and OFN_EXTENSIONDIFFERENT) <> 0 then
Options := Options + [ofExtensionDifferent] else
Options := Options - [ofExtensionDifferent];
if (Flags and OFN_READONLY) <> 0 then
Options := Options + [ofReadOnly] else
Options := Options - [ofReadOnly];
Außerdem wirst du noch über das hier stolpern, was auf private Methoden aus Dialogs.pas zugreift:
if (ofOldStyleDialog in FOptions) or not NewStyleControls then
lpfnHook := DialogHook
else
lpfnHook := ExplorerHook;
Du kannst die vier Zeilen auskommentieren.
Sodann installierst du das Package (im Projektmanager: Rechtsklick|Installieren) und hast in der Tool-Palette deine neue Komponente zur Verfügung.
(Bonusaufgabe für Sharkbyte, falls du hier mitliest:
Dir ist sicher aufgefallen, daß ich oben eine Definition für OFN_ENABLESIZING angegeben habe, die im Original nicht drinsteht. Du solltest in der Lage sein, damit dein Problem hier zu lösen und deinen Dialog resizable zu bekommen.)