|
| |
Using BatchExport Function
One of very interesting functions in DAPI is the BatchExport function.
With it you can export properties of multiple directory objects into a file. It
has a counterpart - BatchImport, to do the same operation in reverse. When I was
just starting investigating MS Exchange directory - I thought about a way to
export the whole directory into a file for examination. In fact, it is very
useful to dump the contents of the whole tree (or a sub-tree) for closer look.
The following DELPHI 5 sample demonstrates how to dump 4 specific
attributes for all Addr-Type objects in organization.
procedure TfrmMAIN.btOKClick(Sender: TObject);
const
Classes : array [0..1] of PChar = ('Addr-Type',nil);
var
bep:BEXPORT_PARMS;
deAttributes:PDAPI_ENTRY;
avAttrName:PATT_VALUE;
CountAtt:Integer;
dwResult:DWORD;
begin
if SaveDialog1.Execute then
begin
if Assigned(SiteInfo) then FreeAndNil(SiteInfo);
SiteInfo:=TSiteInfo.Create(Trim(ebESA.Text));
if SiteInfo.GetInfo then
begin
ZeroMemory(@bep, SizeOf( BEXPORT_PARMS ));
// Initialize BEXPORT_PARMS struct
bep.dwDAPISignature := DAPI_SIGNATURE;
bep.pszDSAName:=PCHAR(SiteInfo.SrvName);
bep.dwFlags := DAPI_EXPORT_ALL_CLASSES or
DAPI_EXPORT_HIDDEN or
DAPI_EXPORT_SUBTREE or
DAPI_RAW_MODE;
bep.pszExportFile := PCHAR(SaveDialog1.FileName);
// Base point is current organization object
bep.pszBasePoint := PCHAR(SiteInfo.OrganizationDNString);
// Specify which objects to export. This overrides DAPI_EXPORT_ALL_CLASSES
// in dwFlags.
bep.rgpszClasses := @Classes;
CountAtt:=4;
avAttrName:=DAPIAllocBuffer(SizeOf(ATT_VALUE)*CountAtt,nil);
ZeroMemory(avAttrName,SizeOf(ATT_VALUE)*CountAtt);
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-4)))^:=
PATT_VALUE(ToAttValue('Object-Class',DAPI_TEXT))^;
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-3)))^:=
PATT_VALUE(ToAttValue('Directory Name',DAPI_TEXT))^;
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-2)))^:=
PATT_VALUE(ToAttValue('Proxy-Generator-DLL',DAPI_TEXT))^;
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-1)))^:=
PATT_VALUE(ToAttValue('File-Version',DAPI_TEXT))^;
deAttributes:=DAPIAllocBuffer(SizeOf(DAPI_ENTRY), nil);
ZeroMemory(deAttributes, SizeOf(DAPI_ENTRY));
deAttributes.unAttributes := CountAtt;
deAttributes.ulEvalTag := TEXT_VALUE_ARRAY;
deAttributes.rgEntryValues:=DAPIAllocBuffer(SizeOf(ATT_VALUE)*(CountAtt),deAttributes);
ZeroMemory(deAttributes.rgEntryValues, SizeOf(ATT_VALUE)*(CountAtt));
deAttributes.rgEntryValues:=avAttrName;
bep.pAttributes := deAttributes;
dwResult:=BatchExport(@bep);
if Assigned(avAttrName) then
DAPIFreeMemory(avAttrName);
if Assigned(deAttributes) then
DAPIFreeMemory(deAttributes);
end;
end;
if Assigned(SiteInfo) then FreeAndNil(SiteInfo);
end;
The file named "Dump.txt" may be found in example with the result of this export operation on my Exchange server. In my particular
case it contains 10 exported objects.
If you like to export Mailboxes and DList, change classes to this:
procedure TfrmMAIN.btOKClick(Sender: TObject);
const
Classes : array [0..2] of PChar = ('Mailbox','Distribution-List',nil);
var
....
begin
......
end;
DELPHI 5 compiled example
If you'd like to export the contents of the whole tree, you may do it by using
the following fragment (corresponding sample is BatchExportAll):
procedure TfrmMAIN.btOKClick(Sender: TObject);
var
bep:BEXPORT_PARMS;
deAttributes:PDAPI_ENTRY;
avAttrName:PATT_VALUE;
CountAtt:Integer;
dwResult:DWORD;
begin
if SaveDialog1.Execute then
begin
if Assigned(SiteInfo) then FreeAndNil(SiteInfo);
SiteInfo:=TSiteInfo.Create(Trim(ebESA.Text));
if SiteInfo.GetInfo then
begin
ZeroMemory(@bep, SizeOf( BEXPORT_PARMS ));
// Initialize BEXPORT_PARMS struct
bep.dwDAPISignature := DAPI_SIGNATURE;
bep.pszDSAName:=PCHAR(SiteInfo.SrvName);
bep.dwFlags := DAPI_EXPORT_ALL_CLASSES or
DAPI_EXPORT_HIDDEN or
DAPI_EXPORT_SUBTREE or
DAPI_RAW_MODE;
bep.pszExportFile := PCHAR(SaveDialog1.FileName);
bep.pszBasePoint := PCHAR(SiteInfo.OrganizationDNString);
bep.rgpszClasses := nil;
CountAtt:=2;
avAttrName:=DAPIAllocBuffer(SizeOf(ATT_VALUE)*CountAtt,nil);
ZeroMemory(avAttrName,SizeOf(ATT_VALUE)*CountAtt);
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-2)))^:=
PATT_VALUE(ToAttValue('Object-Class',DAPI_TEXT))^;
PATT_VALUE(ULONG(avAttrName)+ULONG(SizeOf(ATT_VALUE)*(CountAtt-1)))^:=
PATT_VALUE(ToAttValue('Obj-Dist-Name',DAPI_TEXT))^;
deAttributes:=DAPIAllocBuffer(SizeOf(DAPI_ENTRY), nil);
ZeroMemory(deAttributes, SizeOf(DAPI_ENTRY));
deAttributes.unAttributes := CountAtt;
deAttributes.ulEvalTag := TEXT_VALUE_ARRAY;
deAttributes.rgEntryValues:=DAPIAllocBuffer(SizeOf(ATT_VALUE)*(CountAtt), deAttributes);
ZeroMemory(deAttributes.rgEntryValues, SizeOf(ATT_VALUE)*(CountAtt));
deAttributes.rgEntryValues:=avAttrName;
bep.pAttributes := deAttributes;
dwResult:=BatchExport(@bep);
if Assigned(avAttrName) then
DAPIFreeMemory(avAttrName);
if Assigned(deAttributes) then
DAPIFreeMemory(deAttributes);
end;
end;
if Assigned(SiteInfo) then FreeAndNil(SiteInfo);
end;
This code exports only class names and distinguished names for all objects in
the organization. Again, the result of the dump may be found together with
source files. If you look into Dump.txt file in BatchExportAll example,
you'll notice that most of its contents is occupied by Class-Schema and
Attribute-Schema objects, and only a small fraction in the end - by real
physical "instances" of them. This is because my test installation of
MS Exchange is very small - it contains only a few mailboxes.
The fragment above is different from the first one because I don't specify
class names here. In the first sample I have initialized rgpszClasses member of
BEXPORT_PARMS, thus telling that I specifically request Addr-Type objects only.
Also, the number of exported attributes is different - I have decided for the
sake of simplicity only export distinguished names (and class names). If you
want to export other attributes - you need to do extra work initializing its
pAttributes member.
|