Title: Microsoft Antivirus API
Question: How to use IOfficeAntiVirus interface and develop antivirus program for MS Office. Microsoft Antivirus API enables software developers to develop applications that scan Microsoft Office documents before opening them.
Answer:
Microsoft Antivirus API
How to use IOfficeAntiVirus interface and develop antivirus program for MS Office. Microsoft Antivirus API enables software developers to develop applications that scan Microsoft Office documents before opening them.
The Antivirus API also supports scanning Microsoft IE code downloads, such as ActiveX controls.
The primary purpose of this API is to give a software developers the ability to design and implement antivirus software that can be used by all applications.
The antivirus component is a standard ActiveX component you register as an in-process server that supports the MSOfficeAntiVirus component category (CATID_MSOfficeAntiVirus : TGUID = '{56FFCC30-D398-11d0-B2AE-00A0C908FA49}').
IE and MS Office implement the antivirus component as follows:
* Obtain the list of all the installed antivirus components registered as supporting the MSOfficeAntiVirus component category.
* Launch the installed components.
* Query for the IOfficeAntiVirus interface.
* Call IOfficeAntiVirus.Scan method to obtain all the installed components.
* Continue to open the file after the virus scan, regardless of the HRESULT value. The antivirus software warns a user if a file has a known virus but opens the file after the warning. It is up to the user to take action concerning the warning.
{The Antivirus API enables software vendors to develop applications that scan
Microsoft Office documents before opening them. The API also supports
scanning Microsoft Internet Explorer 5 code downloads, such as ActiveXControls
or installs. However, be aware that the Internet Explorer scanning support
applies only to automatic code downloads and not to file downloads or
HTML documents.
The primary purpose of this API is to give independent software vendors (ISVs)
the ability to design and implement scanning software that can be used by
all applications.}
unit msoav;
interface
uses Windows, SysUtils, ActiveX, ComObj, Classes;
const
IID_IOfficeAntiVirus : TGUID = '{56FFCC30-D398-11d0-B2AE-00A0C908FA49}';
//DEFINE_GUID(IID_IOfficeAntiVirus,
//0x56ffcc30, 0xd398, 0x11d0, 0xb2, 0xae, 0x0, 0xa0, 0xc9, 0x8, 0xfa, 0x49);
CATID_MSOfficeAntiVirus : TGUID = '{56FFCC30-D398-11d0-B2AE-00A0C908FA49}';
//DEFINE_GUID(CATID_MSOfficeAntiVirus,
//0x56ffcc30, 0xd398, 0x11d0, 0xb2, 0xae, 0x0, 0xa0, 0xc9, 0x8, 0xfa, 0x49);
type
TInfoStruct = record
fIsFile : boolean;
fIsReadOnly : boolean;
fIsInstalled : boolean;
fIsHTTPDownload : boolean;
end;
//Contains information about the file to be scanned.
{
* cbSize - Integer value that specifies the size of an MSOAVINFO structure.
* hWnd - Handle to the parent window of the Microsoft Office 2000
* application.
* pwzFullPath - Address of a wide character string that contains the full
path of the file about to be opened.
* lpStg - Address of the OLE storage location of the file about to be
* opened.
* pwzHostName - Address of a wide character string that contains the host
application name for the antivirus scanner user interface.
* pwzOrigURL - Address of a wide character string that contains the URL of the
origin of a downloaded file.
}
TMsoavinfo = record
cbSize : integer;
info : ULONG;
wnd : HWND;
FullPath : Pointer;
pwzHostName : PWChar;
pwzOrigURL : PWChar;
end;
//This is the interface an antivirus scanner uses to interact with a host
//application.
IOfficeAntiVirus = interface(IUnknown)
['{56FFCC30-D398-11d0-B2AE-00A0C908FA49}']
function Scan(pmsoavinfo : PChar) : HResult; stdcall;
end;
function TestBit(const Value: Cardinal; const Bit: byte): Boolean;
procedure GetRegisteredAntiviruses(ProgIDs: TStrings);
implementation
function TestBit(const Value: Cardinal; const Bit: byte): Boolean;
begin
Result := (Value and (1 shl (Bit mod 32))) 0;
end;
procedure GetRegisteredAntiviruses(ProgIDs: TStrings);
var
CatInformation: ICatInformation;
Enum: IEnumGUID;
CLSID: TGUID;
nFetched: Cardinal;
CatId: TGUID;
begin
CatInformation := CreateComObject(CLSID_StdComponentCategoryMgr) as ICatInformation;
CatId := CATID_MSOfficeAntiVirus;
OleCheck(CatInformation.EnumClassesOfCategories(1, @CatId, 0, nil, Enum));
ProgIDs.BeginUpdate;
try
ProgIDs.Clear;
while (Enum.Next(1, CLSID, nFetched) = S_OK) do
ProgIDs.Add(GuidToString(clsid));
finally
ProgIDs.EndUpdate;
end;
end;
end.
Now I will show a small example how to use IOfficeAntiVirus interface to implement own antivirus program for Microsoft Office.
library msoavtest;
uses
ComServ,
msoav,
umsoavtest;
exports
DllGetClassObject,
DllCanUnloadNow,
DllRegisterServer,
DllUnregisterServer;
begin
end.
unit umsoavtest;
interface
uses
Windows, ActiveX, ComObj, ShlObj, Dialogs, msoav;
type
TMSOTest = class(TComObject, IOfficeAntiVirus)
protected
function Scan(pmsoavinfo : PChar) : HResult; stdcall;
end;
const
Class_MsoTest: TGUID = '{F56BE781-C8BE-11D7-8601-00E0184D1E9D}';
implementation
uses ComServ, SysUtils, ShellApi, Registry;
procedure UpdateCat(Register: Boolean; const ClassID: string);
const
SCatImplBaseKey = 'CLSID\%s\Implemented Categories';
SCatImplKey = SCatImplBaseKey + '\%s';
var
CatReg: ICatRegister;
Rslt: HResult;
CatInfo: TCATEGORYINFO;
Description: string;
begin
Rslt := CoCreateInstance(
CLSID_StdComponentCategoryMgr, nil,
CLSCTX_INPROC_SERVER, ICatRegister, CatReg);
if Succeeded(Rslt) then
begin
if Register then
begin
CatInfo.catid := CATID_MSOfficeAntiVirus;
CatInfo.lcid := $0409;
StringToWideChar('', CatInfo.szDescription, Length('') + 1);
OleCheck(CatReg.RegisterCategories(1, @CatInfo));
OleCheck(CatReg.RegisterClassImplCategories(StringToGUID(ClassID), 1, @CATID_MSOfficeAntiVirus));
end
else
begin
OleCheck(CatReg.UnRegisterClassImplCategories(StringToGUID(ClassID), 1, @CATID_MSOfficeAntiVirus));
DeleteRegKey(Format(SCatImplBaseKey, [ClassID]));
end;
end
else
begin
if Register then
begin
CreateRegKey('Component Categories\' + GUIDToString(CATID_MSOfficeAntiVirus), '409', '');
CreateRegKey(Format(SCatImplKey, [ClassID, GUIDToString(CATID_MSOfficeAntiVirus)]), '', '');
end
else
begin
DeleteRegKey(Format(SCatImplKey, [ClassID, GUIDToString(CATID_MSOfficeAntiVirus)]));
DeleteRegKey(Format(SCatImplBaseKey, [ClassID]));
end;
end;
if Register then
begin
Description := GetRegStringValue('CLSID\' + ClassID, '');
CreateRegKey('AppID\' + ClassID, '', Description);
CreateRegKey('CLSID\' + ClassID, 'AppID', ClassID);
end
else
DeleteRegKey('AppID\' + ClassID);
end;
{ TMSOTest }
function TMSOTest.Scan(pmsoavinfo: PChar): HResult;
var
Info : TMsoavinfo;
Struct : TInfoStruct;
p : pointer;
begin
p := pointer(pmsoavinfo);
if not Assigned(p) then
begin
//no information available
Result := S_OK;
Exit;
end;
Move(P^, Info, SizeOf(Tmsoavinfo));
if Info.cbSize SizeOf(Tmsoavinfo) then
begin
//wrong size of the structure
Result := S_OK;
Exit;
end;
Struct.fIsFile := TestBit(Info.Info, 0);
Struct.fIsReadOnly := TestBit(Info.Info, 1);
Struct.fIsInstalled := TestBit(Info.Info, 2);
Struct.fIsHTTPDownload := TestBit(Info.Info, 3);
if struct.fIsFile then
MessageDlg(PWChar(Info.FullPath), mtWarning, [mbOK], 0);
Result := S_OK;
end;
type
TMSOAvFactory = class(TComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
procedure TMSOAVFactory.UpdateRegistry(Register: Boolean);
var
ClassID: string;
begin
ClassID := GUIDToString(Class_MsoTest);
if Register then
begin
inherited UpdateRegistry(Register);
UpdateCat(true, ClassID);
end
else
begin
UpdateCat(false, ClassID);
inherited UpdateRegistry(Register);
end;
end;
initialization
TComObjectFactory.Create(ComServer, TMsoTest, Class_MsoTest,
'MsoTest', '', ciMultiInstance, tmApartment);
end.