Wie moze ktos gdzie moge znalezc cos na temat OLE2 Storage i czy sa jakies moduly oblugujace ten format plikow?
W delphi znajdziesz plik ole2.pas.
Tam jest coś takiego:
{ IStorage interface }
TSNB = ^POleStr;
{$EXTERNALSYM IStorage}
IStorage = class(IUnknown)
public
function CreateStream(pwcsName: POleStr; grfMode: Longint; reserved1: Longint;
reserved2: Longint; var stm: IStream): HResult; virtual; stdcall; abstract;
function OpenStream(pwcsName: POleStr; reserved1: Pointer; grfMode: Longint;
reserved2: Longint; var stm: IStream): HResult; virtual; stdcall; abstract;
function CreateStorage(pwcsName: POleStr; grfMode: Longint;
dwStgFmt: Longint; reserved2: Longint; var stg: IStorage): HResult;
virtual; stdcall; abstract;
function OpenStorage(pwcsName: POleStr; stgPriority: IStorage;
grfMode: Longint; snbExclude: TSNB; reserved: Longint;
var stg: IStorage): HResult; virtual; stdcall; abstract;
function CopyTo(ciidExclude: Longint; rgiidExclude: PIID;
snbExclude: TSNB; stgDest: IStorage): HResult; virtual; stdcall; abstract;
function MoveElementTo(pwcsName: POleStr; stgDest: IStorage;
pwcsNewName: POleStr; grfFlags: Longint): HResult; virtual; stdcall; abstract;
function Commit(grfCommitFlags: Longint): HResult; virtual; stdcall; abstract;
function Revert: HResult; virtual; stdcall; abstract;
function EnumElements(reserved1: Longint; reserved2: Pointer; reserved3: Longint;
var enm: IEnumStatStg): HResult; virtual; stdcall; abstract;
function DestroyElement(pwcsName: POleStr): HResult; virtual; stdcall; abstract;
function RenameElement(pwcsOldName: POleStr;
pwcsNewName: POleStr): HResult; virtual; stdcall; abstract;
function SetElementTimes(pwcsName: POleStr; const ctime: TFileTime;
const atime: TFileTime; const mtime: TFileTime): HResult;
virtual; stdcall; abstract;
function SetClass(const clsid: TCLSID): HResult; virtual; stdcall; abstract;
function SetStateBits(grfStateBits: Longint; grfMask: Longint): HResult;
virtual; stdcall; abstract;
function Stat(var statstg: TStatStg; grfStatFlag: Longint): HResult;
virtual; stdcall; abstract;
end;
Opis tego, to chyba najlepiej w MSDN Library.
IStorage : IUnknownThis interface provides methods for creating and managing the root storage, child storage, and stream objects. These methods can create, open, enumerate, move, copy, rename, or delete the elements in the storage object.
The IStorage interface supports the creation and management of structured storage objects. Structured storage allows hierarchical storage of information within a single file, and is often referred to as ?a file system within a file?. Elements of a structured storage object are storages and streams. Storages are analogous to directories, and streams are analogous to files. Within a structured storage there will be a primary storage object that may contain substorages, possibly nested, and streams. Storages provide the structure of the object, and streams contain the data, which is manipulated through the IStream interface.
(...)
Pozdrrawiam..
Zapomniałem dodać linka:
http://msdn.microsoft.com/library/default.asp?url=/archive/en-us/dnarolegen/html/msdn_ole2b.asp
Wilekie dzieki zaraz sie do roboty biore :D. Niestety to co mi podales jest dla c i nie przeklada sie to na delphi wiec jakby ktos wiedzial gdzie mozna znalezc takie cos ale dla dlephi to bede wdzieczny.
Natknolem sie na kolejny problem... przy wywolywaniu metody OpenStorage z klasy IStorage wyskakuje mi Abstract Error.
procedure TForm1.Button1Click(Sender: TObject);
var
fName : array[0..100] of WideChar;
data : IStorage;
begin
data:=IStorage.Create;
StringToWideChar(edit1.Text, fName, Length(edit1.Text)+1);
data.OpenStorage(fName,nil,STGM_READ,nil,0,data);
end;
stopak napisał(a)
Natknolem sie na kolejny problem... przy wywolywaniu metody OpenStorage z klasy IStorage wyskakuje mi Abstract Error.
procedure TForm1.Button1Click(Sender: TObject);
var
fName : array[0..100] of WideChar;
data : IStorage;
begin
data:=IStorage.Create;
StringToWideChar(edit1.Text, fName, Length(edit1.Text)+1);
data.OpenStorage(fName,nil,STGM_READ,nil,0,data);
end;
IStorage
jest klasą abstrakcyjną (interface) i nie możesz utworzyć jej instancji. Spróbuj skorzystać z StgCreateStorageEx lub StgOpenStorageEx.
PS. Poczytaj jeszcze o IUnknown::AddRef i IUnknown::Release
Można też w ten sposób:
Nie jestem 100% pewien, ale chyba działa.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,activex;
type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
PStorage : IStorage;
PPersistStream: IPersistStream;
PStream : IStream;
WideName,StreamName : array[0..1023] of WideChar;
Hr : HRESULT;
begin
CoInitialize(nil);
PStorage := nil;
PStream := nil;
StringToWideChar(edit1.Text, WideName, Length(edit1.Text)+1);
StringToWideChar('Stream1', WideName, Length('Stream1')+1);
hr := StgCreateDocfile(@WideName,
STGM_CREATE or STGM_TRANSACTED or STGM_READWRITE or STGM_SHARE_EXCLUSIVE,
0, PStorage);
if Failed(Hr) then Exit;
hr := PStorage.CreateStream(@StreamName,
STGM_WRITE or STGM_CREATE or STGM_SHARE_EXCLUSIVE,
0, 0, PStream);
if Failed(Hr) then Exit;
//na koniec
PStream := nil;
PStorage := nil;
CoUninitialize();
end;
end.
wielkie dzieki zaraz sprawdze czy dziala i odpisze :D.
I powstal nastepny problem :D dlaczego jak drugi raz wywoluje read z klasy IStream to wywala mi blad?
procedure TForm1.Button1Click(Sender: TObject);
var
fName,sName : array[0..100] of WideChar;
hr: HRESULT;
data: IStorage;
stream: IStream;
Id: head;
sdata:byte;
begin
StringToWideChar(edit1.Text, fName, Length(edit1.Text)+1);
StringToWideChar('Workbook', sName, Length('Workbook')+1);
if (StgIsStorageFile(fName) = S_OK) then
begin
hr := StgOpenStorage(fName,Nil,STGM_READ or STGM_SHARE_EXCLUSIVE or STGM_DIRECT,Nil,0,data);
if (hr <> S_OK) then
begin
ShowMessage('Cannot open storage file.');
Exit;
end;
hr := data.OpenStream(sName,nil,STGM_READ or STGM_SHARE_EXCLUSIVE or STGM_DIRECT,0,stream);
if (hr <> S_OK) then
begin
ShowMessage('Cannot open data stream.');
Exit;
end;
hr := stream.Read(@id,4,nil);
stream.Read(@sdata,2,nil);
if (hr <> S_OK) then
begin
ShowMessage('Cannot read data from stream.');
Exit;
end;
Memo1.Lines.Add(IntToStr(id.Id));
Memo1.Lines.Add(IntToStr(id.DSize));
Memo1.Lines.Add(IntToStr(Sdata));
end
else
ShowMessage('There is no storage file like: '+WideCharToString(fName));
end;
Nie wiem, być może się myle (nie programuje w Delphi) ale zadeklarowałeś
sdata:byte;
a czytasz tak stream.read(@SDATA,2,nil);
. Czyli zapisujesz do 1-bajtowej zmiennej dwa bajty i tu pewnie ten błąd ;)
Może te 2 funkcje jakoś pomogą:
function SaveGraphFile(pGraph: IGraphBuilder; wszPath: WideString): HRESULT;
var
Storage: IStorage;
Stream: IStream;
Persist: IPersistStream;
begin
Result := StgCreateDocfile(
PWideChar(wszPath),
STGM_CREATE or STGM_TRANSACTED or STGM_READWRITE or STGM_SHARE_EXCLUSIVE,
0, Storage);
if FAILED(Result) then Exit;
Result := Storage.CreateStream(
PWideChar(wszStreamName),
STGM_WRITE or STGM_CREATE or STGM_SHARE_EXCLUSIVE,
0, 0, Stream);
if FAILED(Result) then Exit;
pGraph.QueryInterface(IID_IPersistStream, Persist);
Result := Persist.Save(Stream, True);
Stream := nil;
Persist := nil;
if SUCCEEDED(Result) then Result := Storage.Commit(STGC_DEFAULT);
Storage := nil;
end;
//------------------*******************-------------------
function LoadGraphFile(pGraph: IGraphBuilder; const wszName: WideString): HRESULT;
var
Storage: IStorage;
Stream: IStream;
PersistStream: IPersistStream;
begin
if (S_OK <> StgIsStorageFile(PWideChar(wszName))) then
begin
Result := E_FAIL;
Exit;
end;
Result := StgOpenStorage(PWideChar(wszName), nil,
STGM_TRANSACTED or STGM_READ or STGM_SHARE_DENY_WRITE,
nil, 0, Storage);
if FAILED(Result) then Exit;
Result := pGraph.QueryInterface(IID_IPersistStream, PersistStream);
if (SUCCEEDED(Result)) then
begin
Result := Storage.OpenStream(PWideChar(wszStreamName), nil,
STGM_READ or STGM_SHARE_EXCLUSIVE, 0, Stream);
if SUCCEEDED(Result) then
begin
Result := PersistStream.Load(Stream);
Stream := nil;
end;
PersistStream := nil;
end;
Storage := nil;
end;
No moze teraz ciut od tematu odbiegne ale mam pytanie co nalezy robic po wczytaniu streamu Workbook BOF o nazwie = workbook globals? oczywiscie mowimy tu o formacie plikow excela .xls
Oj, tu by sie przydała jakaś książka typu (Excel 2003 VBA Programmer's Reference)
Ja jedynie mogę polecić lekturę MSDN.
EXCELlent Office Adventures
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnofftalk/html/office01042001.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnexvba/html/odc_5709_chap05idx.asp
itp.
Tutaj raczej chodzi o Opis Formatu Excelowskiego mam ten z openoffice ale tam tego nie moge znalezc :(.
Udalo mi sie zdobyc najnowszy Opis Formatu Excela ale mam taki problem kiedy wczytuje kolejny rekord po BOF dostaje wartość hexadecymalna 00E1 ktora nie wystepuje w tym opsie co robic??