I am wondering if I have a signature problem similar to before. Can you check the attached signatures and constant for me?
Code: Select all
library d_itunes4;
uses
SysUtils,
Classes,
Variants,
ActiveX,
Windows,
ComObj,
DeviceiTunes in 'DeviceiTunes.pas',
DeviceUI in 'DeviceUI.pas',
DeviceCommon in '..\DeviceCommon.pas',
Structs in '..\Structs.pas',
IDUnit in 'IDUnit.pas',
itunesapp in 'itunesapp.pas',
Sync in 'Sync.pas',
HashString in '..\HashString.pas',
Misc in '..\Misc.pas',
FQN in 'FQN.pas',
itTrackCache in 'itTrackCache.pas',
tssUnit in 'tssUnit.pas',
Reg in 'Reg.pas',
LogUnit in '..\LogUnit.pas',
StatUnit in 'StatUnit.pas',
MMUnit in '..\MMUnit.pas',
ConfigUI in 'ConfigUI.pas',
deviceListUnit in '..\deviceListUnit.pas',
niRegularExpression in '..\niRegularExpression.pas',
niSTRING in '..\niSTRING.pas',
BlacklistUnit in '..\BlacklistUnit.pas',
PlaylistUnit in 'PlaylistUnit.pas',
ConfigUnit2 in 'ConfigUnit2.pas',
iTunesLib_TLB3 in 'iTunesLib_TLB3.pas',
HostnameUnit in '..\HostnameUnit.pas',
GlobalUnit1 in 'GlobalUnit1.pas',
MetaUnit1 in 'MetaUnit1.pas',
M3uUnit1 in 'M3uUnit1.pas',
exeUnit in '..\exeUnit.pas',
SongsDB_TLB in '..\SongsDB_TLB.pas';
{$R *.res}
const
PluginName : WideString = 'd_itunes4.dll';
// MANDANTORY: This function is called during plug-in initialization, MMCookies is used to get IDispatch interface to MM.
procedure DEVICE_Init( MMCookie : cardinal); stdcall;
begin
// log.text(3,'DEVICE_Init start'); no log available
try
// assign the interface pointers for the life of the plugin
MMInit( MMCookie) ;
// create the device variables
DeviceItunesInit(pluginname);
except
on e: exception do
log.exception('DEVICE_Init', e);
end;
log.text(3,'DEVICE_Init end');
end;
// MANDANTORY: This should clean up everything.
procedure DEVICE_Quit; stdcall;
begin
log.text(3,'DEVICE_Quit start');
try
DeviceItunesDone;
// unassign the interfaces
MMDone ;
except
// on e: exception do
// log.exception('DEVICE_Quit', e);
end;
// log.text(3,'DEVICE_Quit end'); can't log as log is closed
end;
// OPTIONAL: If implemented, MM calls this whenever WM_DeviceChange message is broadcasted.
// This way plug-in doesn't have to create a window in order to receieve this message.
//function DEVICE_WM_DeviceChange( wParam, lParam : integer) : integer; stdcall;
//begin
// result := 0;
// DeviceChange( wParam, lParam);
//end;
// OPTIONAL: When called, plug-in should try to disconnect the device from system.
function DEVICE_Eject( DeviceHandle : integer) : boolean; stdcall;
begin
log.text(3,'DEVICE_Eject');
result := DeviceiTunesEjectDevice( deviceHandle );
log.text(3,'DEVICE_Eject end');
end;
// MANDANTORY: Returns several boolean flags (based on flag parameter).
function DEVICE_GetFlag( DeviceHandle : integer; flag : integer) : boolean; stdcall;
var
show:boolean;
begin
show:=((flag<>dflCannotScanContent) and (flag<>dflCanEject));
if show then log.text(3,'DEVICE_GetFlag start '+inttostr(flag),DeviceHandle);
// the default
result := false;
try
case flag of
dflFullSynchStart:
result:=DeviceiTunesSyncFullStart(DeviceHandle,false);
dflSynchStart:
DeviceiTunesSyncStart(DeviceHandle,false);
dflSynchEnd:
DeviceiTunesSyncEnd(DeviceHandle);
dflFullSynchEnd:
DeviceiTunesSyncFullEnd(DeviceHandle);
dflSupportsM3U : result := true; // we have playlists
dflForceSettings : result:=true; // If plug-in wants to modify some default device settings
dflNotArtistPlst, dflNotAlbumPlst : result := true;
dflDeleteUnused : result := true;
dflDisableM3USupportConf, dflDisableM3UFolderConf : result := true ;
dflCannotScanContent : result := true ; // we never allow content to be background scanned
dflCreateOnlyCustomNodes : result := true; // we have "special nodes"
dflNoDestinationConf : result := true ; // Keeps Destination configuration hidden for the user
// dflCanRebuildDB: result := true ;
dflNoPlstFilesystemReady : result := true ; // we allow '/' within file names
end;
except
on e: exception do
begin
log.exception('DEVICE_GetFlag '+inttostr(flag), e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
if show then log.text(3,'DEVICE_GetFlag end ',inttostr(flag)+'='+booltostr(result));
end;
// OPTIONAL: Rebuilds internal device library. It's up to the plug-in to show all the UI, etc.
//function DEVICE_RebuildDB( DeviceHandle : integer) : boolean; stdcall;
//begin
// log.text(3,'DEVICE_GetFlag start');
//
// result := false;
// log.text(3,'DEVICE_GetFlag end');
//end;
// OPTIONAL: Initializes the option sheet for the device (i.e. prepares checkboxes, labels, etc.)
function DEVICE_InitOptions( DeviceID : PWideChar; PanelCookie : cardinal) : boolean; stdcall;
var
intf : IDispatch;
PanelInterf : ISDBUIPanel; //Variant;
begin
log.text(3,'DEVICE_InitOptions start');
result := true;
try
//unmarshal
GIT.GetInterfaceFromGlobal( PanelCookie, IDispatch, intf);
PanelInterf := ISDBUIPanel(intf);
UIInitSettingSheet( DeviceID,PanelInterf);
except
on e: exception do
log.exception('DEVICE_InitOptions', e);
end;
log.text(3,'DEVICE_InitOptions end');
end;
// OPTIONAL: Closes the option sheet for the device. If save is TRUE the values should be saved somewhere.
procedure DEVICE_CloseOptions( DeviceID : PWideChar; Save : boolean); stdcall;
begin
log.text(3,'DEVICE_CloseOptions start');
try
UICloseSettingSheet( DeviceID , Save, false);
except
on e: exception do
log.exception('DEVICE_CloseOptions', e);
end;
log.text(3,'DEVICE_CloseOptions end');
end;
// OPTIONAL: Is called to let plug-in to add own nodes to Device node
// 'Start' - if TRUE the nodes will be added above folders, else below
function DEVICE_AddNodes( DeviceHandle : integer; NodeCookie : cardinal; Start : boolean) : boolean; stdcall;
var
// intf : IDispatch;
NodeInterf : SDBTreeNode;
begin
log.text(3,'DEVICE_AddNodes start');
result := true;
try
//unmarshal
GIT.GetInterfaceFromGlobal( NodeCookie, SDBTreeNode, NodeInterf);
UIAddNodes( DeviceiTunesDeviceByHandle(DeviceHandle) , NodeInterf, Start);
except
on e: exception do
log.exception('DEVICE_AddNodes', e);
end;
log.text(3,'DEVICE_AddNodes end');
end;
// OPTIONAL: Returns true if the file can be played by the device (i.e. it will be copied to the device)
// If not implemented, all filetypes supported by MM are synchronized
function DEVICE_CanPlay( DeviceHandle : integer; fname: WideString): boolean; stdcall;
begin
log.text(3,'DEVICE_CanPlay start',fname);
result:=false;
try
result:=iTunesCanPlay(fname);
// ext := WideUpperCase( ExtractFileExt( fname));
// result := (ext='.MP3') or
// (ext='.AAC') or
// (ext='.AIFF') or
// (ext='.M4A') or
// (ext='.M4B') or
// (ext='.M4P') or
// (ext='.WAV') or
// (ext='.') or
// (ext='');
except
on e: exception do
log.exception('DEVICE_CanPlay '+fname+' '+booltostr(result), e);
end;
log.text(3,'DEVICE_CanPlay end');
end;
// OPTIONAL: Returns the total space of the device
function DEVICE_TotalBytes( DeviceHandle : integer) : int64; stdcall;
begin
log.text(3,'DEVICE_TotalBytes start');
Result:=0;
try
result := DeviceiTunesCapacity(DeviceHandle );
except
on e: exception do
begin
log.exception('DEVICE_TotalByte' , e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_TotalBytes end');
end;
// OPTIONAL: Returns available space on the device
function DEVICE_AvailBytes( DeviceHandle : integer) : int64; stdcall;
begin
log.text(3,'DEVICE_AvailBytes start');
Result:=0;
try
Result := DeviceiTunesFreespace(DeviceHandle );
except
on e: exception do
log.exception('DEVICE_AvailBytes' , e);
end;
log.text(3,'DEVICE_AvailBytes end');
end;
// dstDeviceName = 1; // Device name to be shown to user
// dstDefaultM3U = ; // Default path for export of m3us
// dstDefaultMask = 3; // Default mask for exporting tracks
// dstDefaultDontDelete = 4; // Default folders/masks that shouldn't be deleted (e.g. '*.mp4' for iPods)
// dstAlwaysDontDelete = 5; // Folders/masks that shouldn't be ever deleted (e.g. '\iPod_Control\Games_RO\' for iPods)
function DEVICE_GetString( DeviceHandle : integer; strid : integer) : PWideChar; stdcall;
begin
log.text(3,'DEVICE_GetString start',strid);
Result:=nil;
try
case strid of
dstDeviceName :
result := PWideChar( PluginName );
dstDefaultM3U :
begin
result := ''; //PWideChar(iTunesMMFolder());
end;
dstDefaultMask :
begin
// result := '%O'; // full path
result := ''; // deafult
end;
else
result := nil;
end;
except
on e: exception do
begin
log.exception('DEVICE_GetString '+inttostr(strid) , e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_GetString end',result);
end;
// OPTIONAL: Notifies about a file that was deleted/modified during synchronization
// TrackCookie = 0 - Filename was deleted
// TrackCookie <>0 - Filaname was modified, TrackCookie is source for SDBSongData object
procedure DEVICE_NotifyFile( DeviceHandle : integer;
TrackCookie : cardinal;
FileName : String;
flags : integer); stdcall;
var
Track : ISDBSongData;
begin
log.text(3,'DEVICE_NotifyFile start filename/flags=',Filename,flags);
try
// if (flags and dnfDelete) <>0 then
// iTunesNotifyFile( nil, FileName, flags)
// else
if (flags and dnfRemovePlaylist) <>0 then
else
track:=nil;
begin
GIT.GetInterfaceFromGlobal( TrackCookie, ISDBSongData, Track);
end ;
DeviceiTunesNotifyFile( DeviceHandle ,Track, FileName, flags);
except
on e: exception do
begin
log.exception('DEVICE_NotifyFile', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_NotifyFile end');
end;
function DEVICE_UploadTrack( DeviceHandle : integer; TrackCookie : cardinal; SourcePath, TargetPath : PWideChar;
callback : TProgressCallback; callback_context : pointer) : integer; stdcall;
var
Track : ISDBSongData;
begin
log.text(3,'DEVICE_UploadTrack start',sourcepath);
Result := 0;
try
if TrackCookie=0 then
Track:= nil
else
GIT.GetInterfaceFromGlobal( TrackCookie, ISDBSongData, Track);
result := 0 ;
DeviceiTunesUploadTrack( DeviceHandle , Track, SourcePath, TargetPath, callback, callback_context);
except
on e: exception do
begin
log.exception('DEVICE_UploadTrack', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_UploadTrack end');
end;
//procedure DEVICE_NotifyPlaylist( DeviceHandle : integer; M3UFileName, M3UTitle : PWideChar;
// TrackCount : integer; Tracks : PWideCharArr); stdcall;
procedure DEVICE_NotifyPlaylist( DeviceHandle : integer; M3UFileName, M3UTitle : PWideChar;
TrackCount : integer; Tracks : PWideCharArr; M3UPath: PWideChar); stdcall;
begin
log.text(3,'DEVICE_NotifyPlaylist start',M3UTitle,TrackCount);
try
DeviceiTunesCreatePlaylist( DeviceHandle , M3UFileName, M3UTitle, TrackCount, Tracks);
except
on e: exception do
begin
log.exception('DEVICE_NotifyPlaylist', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_NotifyPlaylist end');
end;
function DEVICE_ListContent( DeviceHandle : integer) : PScanResult; stdcall;
begin
log.text(3,'DEVICE_ListContent start');
Result := nil;
try
Result := DeviceiTunesListTracks( DeviceHandle);
except
on e: exception do
begin
log.exception('DEVICE_ListContent', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_ListContent end');
end;
// OPTIONAL: Returns a list of playlists present on the device
function DEVICE_ListPlaylists( DeviceHandle : integer) : PScanResult; stdcall;
begin
log.text(3,'DEVICE_ListPlaylists start');
Result := nil;
try
Result := DeviceiTunesListPlaylists(DeviceHandle );
except
on e: exception do
begin
log.exception('DEVICE_ListPlaylists', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_ListPlaylists end');
end;
// OPTIONAL: Lets plug-in update filenames to match format supported by device (e.g. DOS 8.3 or so)
procedure DEVICE_ModifyFilenames( DeviceHandle : integer; filenamecount:integer; filenamelist : PFileNameRecArr); stdcall;
begin
log.text(3,'DEVICE_ModifyFilenames start',filenamecount);
try
DeviceiTunesFixFilenames( DeviceHandle , filenamecount, filenamelist);
except
on e: exception do
begin
log.exception('DEVICE_ModifyFilenames', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_ModifyFilenames end');
end;
function DEVICE_DeleteFiles( DeviceHandle : integer; filenamecount:integer; filenamelist : PWideCharArr) : boolean; stdcall;
begin
log.text(3,'DEVICE_DeleteFiles start',filenamecount);
Result := false;
try
Result:=DeviceiTunesDeleteFiles( DeviceHandle ,Filenamecount,filenamelist );
except
on e: exception do
begin
log.exception('DEVICE_DeleteFiles', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_DeleteFiles end');
end;
function DEVICE_ReadFile( DeviceHandle : integer; SourcePath, TargetPath : PWideChar;
callback : TProgressCallback; callback_context : pointer) : integer; stdcall;
begin
log.text(3,'DEVICE_ReadFile start');
Result := 0;
try
Result:=DeviceiTunesReadFile( DeviceHandle ,SourcePath, TargetPath , callback , callback_context ) ;
except
on e: exception do
begin
log.exception('DEVICE_ReadFile', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_ReadFile end');
end;
function DEVICE_SetValue( DeviceHandle : integer; DeviceID : PWideChar; valuetype : integer; value : integer): integer; stdcall;
begin
log.text(3,'DEVICE_SetValue start',valuetype,value);
result := 0;
try
DeviceiTunesSetValue(DeviceHandle,valuetype,value);
except
on e: exception do
begin
log.exception('DEVICE_SetValue', e);
DeviceInterf.TerminateThreads(DeviceHandle);
end;
end;
log.text(3,'DEVICE_SetValue end');
end;
//function DEVICE_GetFileMetadata( DeviceHandle : integer; const fname: PChar; TrackCookie: Cardinal): boolean; stdcall;
//begin
// Result:=false;
// try
// ;
// except
// on e: exception do
// log.exception('DEVICE_GetFileMetadata', e);
// end;
//end;
procedure DEVICE_SaveOptions( DeviceID : PWideChar); stdcall;
begin
log.text(3,'DEVICE_SaveOptions start',deviceID);
try
UICloseSettingSheet( DeviceID , True,true);
except
on e: exception do
log.exception('DEVICE_SaveOptions', e);
end;
log.text(3,'DEVICE_SaveOptions end');
end;
exports
DEVICE_Init,
// DEVICE_WM_DeviceChange,
DEVICE_Eject,
// DEVICE_RebuildDB,
DEVICE_GetFlag,
DEVICE_GetString,
DEVICE_AddNodes,
DEVICE_InitOptions,
DEVICE_CloseOptions,
DEVICE_CanPlay,
DEVICE_TotalBytes,
DEVICE_AvailBytes,
DEVICE_NotifyFile,
DEVICE_UploadTrack,
DEVICE_NotifyPlaylist,
DEVICE_ListPlaylists,
DEVICE_ModifyFilenames,
DEVICE_ListContent,
DEVICE_DeleteFiles,
DEVICE_ReadFile,
DEVICE_SetValue,
// DEVICE_GetFileMetadata, //MM4
DEVICE_SaveOptions, //MM4
DEVICE_Quit;
begin
DisableThreadLibraryCalls(hInstance);
end.
Code: Select all
unit DeviceCommon;
interface
uses ActiveX, Windows;
const
// Flags returned by DEVICE_GetFlags()
dflCanEject = 1; // Plug-in can safely remove the device
dflCanRebuildDB = 2; // Plug-in can rebuild device's internal DB
dflSynchStart = 3; // Notifies about start of any type of synchronization
dflSynchEnd = 4; // Notifies about end of any type of synchronization
dflUseDotsInM3U = 5; // Whether device supports '..\xxx.mp3' paths
dflSupportsM3U = 6; // If m3us are supported at all
dflNotConfigured = 7; // If device is configured at all (otherwise configuration sheet is shown to user by default)
dflFullSynchStart = 8; // Notifies about start of full synchronization (called before dflSynchStart)
dflFullSynchEnd = 9; // Notifies about end of full synchronization (called after dflSynchEnd)
dflNotArtistPlst = 10; // Don't create playlists for artists
dflNotAlbumPlst = 11; // Don't create playlists for album
dflForceSettings = 12; // If plug-in wants to modify some default device settings
dflRandomSelection = 13; // If Random Selection should be turned on (queried only if dflForceSettings is true)
dflDeleteUnused = 14; // Auto-remove audio tracks not in synch list (queried only if dflForceSettings is true)
dflDeleteConfirm = 15; // Confirm tracks deletion (queried only if dflForceSettings is true)
dflNotifyVisibility= 16; // Notifies plug-in about changed visibility of a device
dflDisableM3USupportConf = 17; // Keeps M3U configuration disabled for the user - forcing the default value
dflDisableM3UFolderConf = 18; // Disables configuration of M3U target folder - forcing the default value
dflSupportsReplayGain = 19; // In case device supports Replay Gain (or e.g. Sound Check in case of iPods)
dflCannotScanContent = 22; // MM will not scan and cache device content (only before sync)
dflCreateOnlyCustomNodes = 23; // MM will not create any device subnodes
dflNoDestinationConf = 24; // Keeps Destination configuration hidden for the user
dflNoPlstFilesystemReady = 25; // A new flag dflNoPlstFilesystemReady was added to prevent this whenever needed
// String types for DEVICE_GetString()
dstDeviceName = 1; // Device name to be shown to user
dstDefaultM3U = 2; // Default path for export of m3us
dstDefaultMask = 3; // Default mask for exporting tracks
dstDefaultDontDelete = 4; // Default folders/masks that shouldn't be deleted (e.g. '*.mp4' for iPods)
dstAlwaysDontDelete = 5; // Folders/masks that shouldn't be ever deleted (e.g. '\iPod_Control\Games_RO\' for iPods)
// Notification type for DEVICE_NotifyFile()
dnfDelete = $01; // Notifies that a file was deleted from the device
dnfModified = $02; // Notifies that a file was uploaded to the device
dnfConverted = $04; // Notifies that the file was also converted before uploading to device
dnfTagsModified = $08; // Notifies that a file wasn't uploaded, but its tags were modified in PC and should be reflected in device
dnfIsPodcast = $10; // Notifies that a file is an podcast episode
dnfIsAudiobook = $20; // Notifies that a file is an audiobook track
dnfRemovePlaylist = $40; // Notifies that this playlist should be removed from device
// Value types to be set by DEVICE_SetValue()
dvFirstGenreOnly = 1; // Uses only the first genre in case of multiple values
dvFirstArtistOnly = 2; // Uses only the first artist/composer in case of multiple values
const
CLSID_StdGlobalInterfaceTable : TGUID =
'{00000323-0000-0000-C000-000000000046}';
type
PWideCharArr = ^TWideCharArr;
TWideCharArr = array [0..MAXINT div 4-1] of PWideChar;
PFileNameRec = ^TFileNameRec;
TFileNameRec = record
filename: PWideChar; // at least 256 chars wide buffer for filename
track_id: integer; // track id as in MM.DB file
track_cookie: cardinal; // COM object SDBSongData can be accessed this way
flags: integer; // Not used at this moment
end;
PFileNameRecArr = ^TFileNameRecArr;
TFileNameRecArr = array [0..MAXINT div 32-1] of TFileNameRec;
PScanRecord = ^TScanRecord;
// TScanRecord = record
// filename: PWideChar;
// filesize: int64;
// lastmodified: TDateTime; // i.e. a float
// end;
TScanRecord = record
filename: PWideChar;
filesize: int64;
lastmodified: TDateTime; // i.e. a float
track_cookie: cardinal; // COM object SDBSongData can be accessed this way
end;
PScanResultArr = ^TScanResultArr;
TScanResultArr = array [0..MAXINT div 32-1] of PScanRecord;
PScanResult = ^TScanResult;
TScanResult = record
FileCount: integer;
Files: PScanResultArr;
end;
TProgressCallback = function( context : pointer; percentdone : double) : boolean; stdcall;
TThreadCallFunc = function( context : pointer) : integer; stdcall;
TMainThreadCallFunc = function( callFunc : TThreadCallFunc; context : pointer) : integer; stdcall;
IGlobalInterfaceTable = interface(IUnknown)
['{00000146-0000-0000-C000-000000000046}']
function RegisterInterfaceInGlobal (pUnk : IUnknown; const riid: TIID;
out dwCookie : DWORD): HResult; stdcall;
function RevokeInterfaceFromGlobal (dwCookie: DWORD): HResult; stdcall;
function GetInterfaceFromGlobal (dwCookie: DWORD; const riid: TIID;
out ppv): HResult; stdcall;
end;
const
DBT_DEVICEARRIVAL = $8000; // system detected a new device
DBT_DEVICEQUERYREMOVE = $8001; // wants to remove, may fail
DBT_DEVICEQUERYREMOVEFAILED = $8002; // removal aborted
DBT_DEVICEREMOVEPENDING = $8003; // about to remove, still avail.
DBT_DEVICEREMOVECOMPLETE = $8004; // device is gone
DBT_DEVICETYPESPECIFIC = $8005; // type specific event
DBT_CUSTOMEVENT = $8006; // user-defined event
const
DBT_DEVTYP_OEM = $00000000; // oem-defined device type
DBT_DEVTYP_DEVNODE = $00000001; // devnode number
DBT_DEVTYP_VOLUME = $00000002; // logical volume
DBT_DEVTYP_PORT = $00000003; // serial, parallel
DBT_DEVTYP_NET = $00000004; // network resource
type
PDEV_BROADCAST_HDR = ^DEV_BROADCAST_HDR;
DEV_BROADCAST_HDR = record
dbch_size : integer;
dbch_devicetype : integer;
dbch_reserved : integer;
end;
type
PDEV_BROADCAST_VOLUME = ^DEV_BROADCAST_VOLUME;
DEV_BROADCAST_VOLUME = record
dbcv_size : integer;
dbcv_devicetype : integer;
dbcv_reserved : integer;
dbcv_unitmask : integer;
dbcv_flags : word;
end;
function GIT : IGlobalInterfaceTable;
const
DIID_ISDBUIButtonEvents: TGUID = '{CB4BFF25-1F10-495B-812A-AE78FDC0A163}';
DIID_ISDBTreeNodeEvents: TGUID = '{4114837B-1B8C-43E9-9185-A3BC7BA40742}';
DIID_ISDBApplicationEvents: TGUID = '{ABF1895B-1032-45E1-A119-8926831F7167}';
implementation
function GIT : IGlobalInterfaceTable;
const
cGIT : IGlobalInterfaceTable = NIL;
begin
if (cGIT = NIL) then
CoCreateInstance (CLSID_StdGlobalInterfaceTable, NIL, CLSCTX_ALL,
IGlobalInterfaceTable, cGIT);
Result := cGIT;
end;
end.