![]() |
Zip erstellen über Shell API
Hallo zusammen,
ich habe im Blog von TMS Software folgende Unit gefunden. Mit Ihr lassen sich die windowseigenen Zip_Funktionen zum komprimieren und dekomprimieren nutzen. Sehr komfortabel wenn es funktionieren würde. Die Funktionen kompilieren unter D2010 und D2006 ohne Probleme. Er schmeißt mir aber eine Access Violation beim CopyHere in der Funktion ShellZip. Kann das mal einer von Euch testen ? Irgendwelche erleuchtenden Infos ?
Code:
unit ShellZip;
interface function NumProcessThreads: integer; function ShellZip(zipfile, sourcefolder:string; filter: string = ''): boolean; function ShellUnzip(zipfile, targetfolder: string; filter: string = ''): boolean; implementation uses Comobj, Windows,Tlhelp32; const SHCONTCH_NOPROGRESSBOX = 4; SHCONTCH_AUTORENAME = 8; SHCONTCH_RESPONDYESTOALL = 16; SHCONTF_INCLUDEHIDDEN = 128; SHCONTF_FOLDERS = 32; SHCONTF_NONFOLDERS = 64; function ShellUnzip(zipfile, targetfolder: string; filter: string = ''): boolean; var shellobj: variant; srcfldr, destfldr: variant; shellfldritems: variant; begin shellobj := CreateOleObject('Shell.Application'); srcfldr := shellobj.NameSpace(zipfile); destfldr := shellobj.NameSpace(targetfolder); shellfldritems := srcfldr.Items; if (filter <> '') then shellfldritems.Filter(SHCONTF_INCLUDEHIDDEN or SHCONTF_NONFOLDERS or SHCONTF_FOLDERS,filter); destfldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL); end; function NumProcessThreads: integer; var hsnapshot: THandle; Te32: TTHREADENTRY32; proch: dword; procthreads: integer; begin procthreads := 0; proch := GetCurrentProcessID; hSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); Te32.dwSize := sizeof(TTHREADENTRY32); if Thread32First(hSnapShot, Te32) then begin if te32.th32OwnerProcessID = proch then inc(procthreads); while Thread32Next(hSnapShot, Te32) do begin if te32.th32OwnerProcessID = proch then inc(procthreads); end; end; CloseHandle (hSnapShot); Result := procthreads; end; function ShellZip(zipfile, sourcefolder:string; filter: string = ''): boolean; const emptyzip: array[0..23] of byte = (80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); var ms: TMemoryStream; shellobj: variant; srcfldr, destfldr: variant; shellfldritems: variant; numt: integer; begin if not FileExists(zipfile) then begin // create a new empty ZIP file ms := TMemoryStream.Create; ms.WriteBuffer(emptyzip, sizeof(emptyzip)); ms.SaveToFile(zipfile); ms.Free; end; numt := NumProcessThreads; shellobj := CreateOleObject('Shell.Application'); srcfldr := shellobj.NameSpace(sourcefolder); destfldr := shellobj.NameSpace(zipfile); shellfldritems := srcfldr.Items; if (filter <> '') then shellfldritems.Filter(SHCONTF_INCLUDEHIDDEN or SHCONTF_NONFOLDERS or SHCONTF_FOLDERS,filter); destfldr.CopyHere(shellfldritems, 0); // wait till all shell threads are terminated while NumProcessThreads <> numt do begin sleep(100); end; end; end. |
Re: Zip erstellen über Shell API
Könntest du die genaue Fehlermeldung posten? Also die Accessviolation mit all den angezeigten Adressen und dazugehörigen Operationen.
|
Re: Zip erstellen über Shell API
...aber klar
--------------------------- Tmsshellzipdemo --------------------------- Zugriffsverletzung bei Adresse 004A4C09 in Modul 'TMSShellZipDemo.exe'. Lesen von Adresse 00000000. --------------------------- OK --------------------------- in einem Demoprojekt mit FORM und nur einem Button drauf. |
Re: Zip erstellen über Shell API
Zitat:
Es ist also irgendwo etwas nicht initialisiert. Ich vermute das shellfldritems oder dergleichen nil ist. Am besten du setzt einfach mal einen Haltepunkt und gehst Schritt für Schritt das ganze durch und schaust welchen Wert die Variablen haben. Und noch besser wäre eine Fehlerprüfung rein zu bauen. Also einfach prüfen ob irgendein Funktionsaufruf fehl schlägt (erkennt man meisten am Rückgabewert) und dann auch nur weitermachen wenn alles ok ist. Denn derzeit arbeitet die Funktion alles nacheinander ab selbst wenn irgendwo eine Funktion nicht das notwendige für den weiteren Ablauf zurück gibt. |
Re: Zip erstellen über Shell API
Hallo SirThornberry,
das ist schon klar. Die Funktion ist nur so aus dem Blog kopiert. Ich habe noch keinerlei Veränderungen eingebaut. Da fehlen z.B. auch noch die Rückgabewerte usw. Ich wollte es erstmal im Orginal von TMS (Bruno der Chef) versuchen. Er scheint aber das Shellobject, bzw. Teile davon nicht oder falsch zu initialisieren. Scheinbar kennt er das Objekt und die Propertys aber, da es ja kompiliert. Hast Du es mal bei Dir versucht ? |
Re: Zip erstellen über Shell API
hey ConstantGardener,
Erstmal vorweg: Mich wundert das es sich für dich überhaupt so kompilieren lässt.. da wird doch ein MemoryStream und die Funktion FileExists verwendet?! Also ich musste noch die Classes und SysUtils Units einbinden damit das Ding überhaupt anstandslos kompiliert wird :gruebel: Danach hab ich aber keine Probleme beim erstellen von zip Dateien... Naja bis auf die Tatsache das sich mein Testapp aufgrund der Schleife
Delphi-Quellcode:
bei einigen Archiven aufhängt...
while NumProcessThreads <> numt do
begin sleep(100); end; Beim entpacken in einen Ordner gibt es bei mir nur Probleme wenn der Ordner nicht vorhanden ist... Wo genau kracht es denn bei dir? |
Re: Zip erstellen über Shell API
Ja, da hast Du recht. Die SysUtils fehlen hier im Quelltext. Hatte Sie aber natürlich drin. Frage mich gerade wo die geblieben Sind beim Kopieren. :gruebel:
How ever, kompiliert bekomme ich es. Bei
Delphi-Quellcode:
knallts. Das Zip Archiv bleibt lehr. Unzip hab ich noch garnicht probiert.
destfldr.CopyHere(shellfldritems, 0);
|
Re: Zip erstellen über Shell API
mhhh...
Wie sieht denn dein Aufruf aus? Benutzt du irgendwelche Filter? Wohin willst du die zip Datei schreiben? Schreibrechte vorhanden? Den Fehler bekomm ich namlich auch wenn ich von einem nicht Admin Konto auf C:\ schreiben will... Denn dann setzt
Delphi-Quellcode:
destfldr auf $00000000.
destfldr := shellobj.NameSpace(zipfile);
|
Re: Zip erstellen über Shell API
Zitat:
Die Funktion NameSpace() akzeptiert als Argument nur ein Variant. WideStrings oder Strings führen zu dem Fehler, dass zwar ein Ergebnis vom Typ varDispatch zurückgeliefert wird, aber der Zeiger = nil ist. Leichte Schlamperei von Microsoft! Hier die überarbeitete Unit. Wichtig ist übrigens, dass die Zipdatei mit absolutem Pfad angegeben wird.
Delphi-Quellcode:
unit ShellZipTool;
interface type TShellZip = class(TObject) private FFilter: string; FZipfile: WideString; shellobj: Olevariant; procedure CreateEmptyZip; function GetNameSpaceObj(x:OleVariant):OleVariant; function GetNameSpaceObj_zipfile:OleVariant; public procedure ZipFolder(const sourcefolder:WideString); procedure Unzip(const targetfolder: WideString); property Zipfile:WideString read FZipfile write FZipfile; property Filter:string read FFilter write FFilter; end; function NumProcessThreads: integer; implementation uses Classes, Comobj, Windows, Tlhelp32, SysUtils, Variants; const SHCONTCH_NOPROGRESSBOX = 4; SHCONTCH_AUTORENAME = 8; SHCONTCH_RESPONDYESTOALL = 16; SHCONTF_INCLUDEHIDDEN = 128; SHCONTF_FOLDERS = 32; SHCONTF_NONFOLDERS = 64; function IsValidDispatch(const v:OleVariant):Boolean; begin result := (VarType(v)=varDispatch) and Assigned(TVarData(v).VDispatch); end; function NumProcessThreads: integer; var hsnapshot: THandle; Te32: TTHREADENTRY32; proch: dword; begin Result := 0; proch := GetCurrentProcessID; hSnapShot := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); Te32.dwSize := sizeof(TTHREADENTRY32); if Thread32First(hSnapShot, Te32) then begin if te32.th32OwnerProcessID = proch then inc(Result); while Thread32Next(hSnapShot, Te32) do begin if te32.th32OwnerProcessID = proch then inc(Result); end; end; CloseHandle(hSnapShot); end; { TShellZip } procedure TShellZip.CreateEmptyZip; const emptyzip: array[0..23] of byte = (80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); var ms: TMemoryStream; begin // create a new empty ZIP file ms := TMemoryStream.Create; try ms.WriteBuffer(emptyzip, sizeof(emptyzip)); ms.SaveToFile(Zipfile); finally ms.Free; end; end; function TShellZip.GetNameSpaceObj(x:OleVariant): OleVariant; begin // WARNING: // the argument of .NameSpace must be a OleVariant // don't change "x" to string or WideString Result := shellobj.NameSpace(x); end; function TShellZip.GetNameSpaceObj_zipfile: OleVariant; begin Result := GetNameSpaceObj(Zipfile); if not IsValidDispatch(Result) then raise EInvalidOperation.CreateFmt('<%s> invalid zipfile', [zipfile]); end; procedure TShellZip.ZipFolder(const sourcefolder: WideString); var srcfldr, destfldr: OleVariant; shellfldritems: Olevariant; numt: integer; begin if not FileExists(zipfile) then begin CreateEmptyZip; end; numt := NumProcessThreads; shellobj := CreateOleObject('Shell.Application'); srcfldr := GetNameSpaceObj(sourcefolder); if not IsValidDispatch(srcfldr) then raise EInvalidOperation.CreateFmt('<%s> invalid source', [sourcefolder]); destfldr := GetNameSpaceObj_zipfile; shellfldritems := srcfldr.Items; if (filter <> '') then shellfldritems.Filter(SHCONTF_INCLUDEHIDDEN or SHCONTF_NONFOLDERS or SHCONTF_FOLDERS,filter); destfldr.CopyHere(shellfldritems, 0); // wait till all shell threads are terminated while NumProcessThreads <> numt do begin sleep(100); end; end; procedure TShellZip.Unzip(const targetfolder: WideString); var srcfldr, destfldr: Olevariant; shellfldritems: Olevariant; begin shellobj := CreateOleObject('Shell.Application'); srcfldr := GetNameSpaceObj_zipfile; destfldr := GetNameSpaceObj(targetfolder); if not IsValidDispatch(destfldr) then raise EInvalidOperation.CreateFmt('<%s> invalid target folder', [targetfolder]); shellfldritems := srcfldr.Items; if (filter <> '') then shellfldritems.Filter(SHCONTF_INCLUDEHIDDEN or SHCONTF_NONFOLDERS or SHCONTF_FOLDERS,filter); destfldr.CopyHere(shellfldritems, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL); end; end. |
Re: Zip erstellen über Shell API
Interessantes Thema. Kann man da auch einzelne Dateien oder Dateilisten verwenden oder geht das nur mit Verzeichnissen?
Ist es Absicht, dass die Variablen FFilter und FZipfile nur bei der Deklaration der Properties verwendet werden? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:06 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz