(* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is GeckoSDK for Delphi.
 *
 * The Initial Developer of the Original Code is Takanori Ito.
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** *)
unit nsInit;

interface

uses
  sysutils,Classes,LCLProc,FileUtil,nsXPCOM, nsConsts, nsTypes, nsGeckoStrings
  {$IFDEF MSWINDOWS},registry{$ENDIF}
  ;

// XPCOM Functions
function NS_InitXPCOM2(out servMgr: nsIServiceManager; binDir: nsIFile; appFileLocationProvider: nsIDirectoryServiceProvider): nsresult; cdecl;
function NS_ShutdownXPCOM(servMgr: nsIServiceManager): nsresult; cdecl;
function NS_GetServiceManager(out servMgr: nsIServiceManager): nsresult; cdecl;
function NS_GetComponentManager(out compMgr: nsIComponentManager): nsresult; cdecl;
function NS_GetComponentRegistrar(out compReg: nsIComponentRegistrar): nsresult; cdecl;
function NS_GetMemoryManager(out memMgr: nsIMemory): nsresult; cdecl;
function NS_NewLocalFile(const Path: nsAString; FollowLinks: PRBool; out newFile: nsILocalFile): nsresult; cdecl;
function NS_NewNativeLocalFile(const Path: nsACString; FollowLinks: PRBool; out newFile: nsILocalFile): nsresult; cdecl;
function NS_GetDebug(out debug: nsIDebug): nsresult; cdecl;
function NS_GetTraceRefcnt(out traceRefcnt: nsITraceRefcnt): nsresult; cdecl;

//type
//  PLongBool = ^LongBool;

function NS_StringContainerInit(var aContainer: nsStringContainer): nsresult; cdecl;
procedure NS_StringContainerFinish(var aContainer: nsStringContainer); cdecl;
function NS_StringGetData(const aStr: nsAString; out aData: PWideChar; aTerminated: PLongBool=nil): nsresult; cdecl;
function NS_StringCloneData(const aStr: nsAString): PWideChar; cdecl;
procedure NS_StringSetData(aStr: nsAString; const aData: PWideChar; aDataLength: PRUint32 = High(PRUint32)); cdecl;
procedure NS_StringSetDataRange(aStr: nsAString; aCutOffset, aCutLength: Longword; const aData: PWideChar; aDataLength: PRUint32 = High(PRUint32)); cdecl;
procedure NS_StringCopy(aDestStr: nsAString; const aSrcStr: nsAString); cdecl;
procedure NS_StringAppendData(aStr: nsAString; const aData: PWideChar; aDataLength: PRUint32 = High(PRUint32));
procedure NS_StringInsertData(aStr: nsAString; aOffSet: PRUint32; const aData: PWideChar; aDataLength: PRUint32 = High(PRUint32));
procedure NS_StringCutData(aStr: nsAString; aCutOffset, aCutLength: PRUint32);

function NS_CStringContainerInit(var aContainer: nsCStringContainer): nsresult; cdecl;
procedure NS_CStringContainerFinish(var aContainer: nsCStringContainer); cdecl;
function NS_CStringGetData(const aStr: nsACString; out aData: PAnsiChar; aTerminated: PLongBool=nil): PRUint32; cdecl;
function NS_CStringCloneData(const aStr: nsACString): PAnsiChar; cdecl;
procedure NS_CStringSetData(aStr: nsACString; const aData: PAnsiChar; aDataLength: PRUint32 = High(PRUint32)); cdecl;
procedure NS_CStringSetDataRange(aStr: nsACString; aCutOffset, aCutLength: PRUint32; const aData: PAnsiChar; aDataLength: PRUint32 = High(PRUint32)); cdecl;
procedure NS_CStringCopy(aDestStr: nsACString; const aSrcStr: nsACString); cdecl;
procedure NS_CStringAppendData(aStr: nsACString; const aData: PAnsiChar; aDataLength: Longword = High(PRUint32));
procedure NS_CStringInsertData(aStr: nsACString; aOffSet: PRUint32; const aData: PAnsiChar; aDataLength: PRUint32 = High(PRUint32));
procedure NS_CStringCutData(aStr: nsACString; aCutOffset, aCutLength: PRUint32);

type
  nsSourceEncoding = ( NS_ENCODING_ASCII = 0,
                       NS_ENCODING_UTF8 = 1,
                       NS_ENCODING_NATIVE_FILESYSTEM = 2);

function NS_CStringToUTF16(const aSource: nsACString; aSrcEncoding: nsSourceEncoding; aDest: nsAString): nsresult; cdecl;
function NS_UTF16ToCString(const aSource: nsAString; aSrcEncoding: nsSourceEncoding; aDest: nsACString): nsresult; cdecl;

// Added for Gecko 1.8
type
  nsGetModuleProc = function (aCompMgr: nsIComponentManager; location: nsIFile; out return_cobj: nsIModule): nsresult; cdecl;

  PStaticModuleInfo = ^nsStaticModuleInfo;
  PStaticModuleInfoArray = ^nsStaticModuleInfoArray;
  nsStaticModuleInfo = record
    name: PChar;
    getModule: nsGetModuleProc;
  end;
  nsStaticModuleInfoArray = array[0..MaxInt div Sizeof(nsStaticModuleInfo)-1] of nsStaticModuleInfo;

function NS_Alloc(size: PRSize): Pointer; cdecl;
function NS_Realloc(ptr: Pointer; size: PRSize): Pointer; cdecl;
procedure NS_Free(ptr: Pointer); cdecl;
function NS_InitXPCOM3(out servMgr: nsIServiceManager; binDir: nsIFile; appFileLocationProvider: nsIDirectoryServiceProvider; var staticComponents: nsStaticModuleInfoArray; componentCount: PRUint32): nsresult; cdecl;

function NS_StringContainerInit2(var aContainer: nsStringContainer; const aStr: PWideChar; aOffset, aLength: PRUint32): nsresult; cdecl;
procedure NS_StringSetIsVoid(aStr: nsAString; const aIsVoid: PRBool); cdecl;
function NS_StringGetIsVoid(const aStr: nsAString): PRBool; cdecl;

function NS_CStringContainerInit2(var aContainer: nsCStringContainer; const aStr: PAnsiChar; aOffset, aLength: PRUint32): nsresult; cdecl;
procedure NS_CStringSetIsVoid(aStr: nsACString; const aIsVoid: PRBool); cdecl;
function NS_CStringGetIsVoid(const aStr: nsACString): PRBool; cdecl;

// Added for Gecko 1.9
const
  TD_INT8               = 0;
  TD_INT16              = 1;
  TD_INT32              = 2;
  TD_INT64              = 3;
  TD_UINT8              = 4;
  TD_UINT16             = 5;
  TD_UINT32             = 6;
  TD_UINT64             = 7;
  TD_FLOAT              = 8;
  TD_DOUBLE             = 9;
  TD_BOOL               = 10;
  TD_CHAR               = 11;
  TD_WCHAR              = 12;
  TD_VOID               = 13;
  TD_PNSIID             = 14;
  TD_DOMSTRING          = 15;
  TD_PSTRING            = 16;
  TD_PWSTRING           = 17;
  TD_INTERFACE_TYPE     = 18;
  TD_INTERFACE_IS_TYPE  = 19;
  TD_ARRAY              = 20;
  TD_PSTRING_SIZE_IS    = 21;
  TD_PWSTRING_SIZE_IS   = 22;
  TD_UTF8STRING         = 23;
  TD_CSTRING            = 24;
  TS_ASTRING            = 25;

type
  nsXPTType = record
    flags: PRUint8;
  end;

  nsxPTCMiniVariant = record
  case Integer of
  TD_INT8:              (i8: PRInt8);
  TD_INT16:             (i16: PRInt16);
  TD_INT32:             (i32: PRInt32);
  TD_INT64:             (i64: PRInt64);
  TD_UINT8:             (u8: PRUint8);
  TD_UINT16:            (u16: PRUint16);
  TD_UINT32:            (u32: PRUint32);
  TD_UINT64:            (u64: PRUint64);
  TD_FLOAT:             (f: Single);
  TD_DOUBLE:            (d: Double);
  TD_BOOL:              (b: PRBool);
  TD_CHAR:              (c: AnsiChar);
  TD_WCHAR:             (w: WideChar);
  TD_VOID:              (p: Pointer);
  end;

  nsXPTCVariant = record
    val: nsXPTCMiniVariant;
    ptr: Pointer;
    type_: nsXPTType;
    flags: PRUint32;
  end;

  PXPTCVariantArray = ^nsXPTCVariantArray;
  nsXPTCVariantArray = array [0..MaxInt div SizeOf(nsXPTCVariant)-1] of nsXPTCVariant;
  PXPTCMiniVariantArray = ^nsXPTCMiniVariantArray;
  nsXPTCMiniVariantArray = array [0..MaxInt div SizeOf(nsXPTCMiniVariant)-1] of nsXPTCMiniVariant;

  XPTTypeDescriptorPrefix = record
    flags: PRUint8;
  end;

  XPTTypeDescriptor = record
    prefix: XPTTypeDescriptorPrefix;
    argnum: PRUint8;
    argnim2: PRUint8;
    case Integer of
    TD_INTERFACE_TYPE:  (iface: PRUint16);
    TD_ARRAY:           (additional_type: PRUint16);
  end;

  PXPTParamDescriptor = ^XPTParamDescriptor;
  XPTParamDescriptor = record
    flags: PRUint8;
    type_: XPTTypeDescriptor;
  end;
  PXPTParamDescriptorArray = ^XPTParamDescriptorArray;
  XPTParamDescriptorArray = array [0..MaxInt div SizeOf(XPTParamDescriptor)-1] of XPTParamDescriptor;

  XPTMethodDescriptor = record
    name: PAnsiChar;
    params: PXPTParamDescriptorArray;
    result: PXPTParamDescriptor;
    flags: PRUint8;
    num_args: PRUint8;
  end;

  nsIXPTCProxy = interface(nsISupports)
    function CallMethod(aMethodIndex: PRUint16; const aInfo: XPTMethodDescriptor; aParams: PXPTCMiniVariantArray): nsresult; stdcall;
  end;


procedure NS_DebugBreak(aSeverity: PRUint32; aStr: PAnsiChar; aExpr: PAnsiChar; aFile: PAnsiChar; aLine: PRUint32); cdecl;
procedure NS_LogInit(); cdecl;
procedure NS_LogTerm(); cdecl;
procedure NS_LogAddRef(aPtr: Pointer; aNewRefCnt: nsrefcnt; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
procedure NS_LogRelease(aPtr: Pointer; aNewRefCnt: nsrefcnt; aTypeName: PAnsiChar); cdecl;
procedure NS_LogCtor(aPtr: Pointer; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
procedure NS_LogDtor(aPtr: Pointer; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
procedure NS_LogCOMPtrAddRef(aCOMPtr: Pointer; aObject: nsISupports); cdecl;
procedure NS_LogCOMPtrRelease(aCOMPtr: Pointer; aObject: nsISupports); cdecl;

function NS_GetXPTCallStub(aIID: TGUID; aOuter: nsIXPTCProxy; out aStub): nsresult; cdecl;
procedure NS_DestroyXPTCallStub(aStub: nsISupports); cdecl;
function NS_InvokeByIndex(that: nsISupports; methodIndex: PRUint32; paramCount: PRUint32; params: PXPTCVariantArray): nsresult; cdecl;

// GLUE Types
type
  PGREVersionRange = ^TGREVersionRange;
  TGREVersionRange = record
    lower: PAnsiChar;
    lowerInclusive: PRBool;
    upper: PAnsiChar;
    upperInclusive: PRBool;
  end;
  TGREVersionRangeArray = array [0..MaxInt div SizeOf(TGREVersionRange)-1] of TGREVersionRange;

  PGREProperty = ^TGREProperty;
  TGREProperty = record
    property_: PAnsiChar;
    value: PAnsiChar;
  end;
  TGREPropertyArray = array [0..MaxInt div SizeOf(TGREProperty)-1] of TGREProperty;

  PNSFuncPtr = ^NSFuncPtr;
  NSFuncPtr = procedure (); cdecl;
  PDynamicFunctionLoad = ^TDynamicFunctionLoad;
  TDynamicFunctionLoad = record
    functionName: PAnsiChar;
    function_: Pointer;
  end;
  PDynamicFunctionLoadArray = ^TDynamicFunctionLoadArray;
  TDynamicFunctionLoadArray = array [
    0..MaxInt div SizeOf(TDynamicFunctionLoad)-1
    ] of TDynamicFunctionLoad;

// GLUE Functions
{$IFDEF MSWINDOWS}
function GRE_GetGREPathWithProperties(
                aVersions: PGREVersionRange;
                versionsLength: PRUint32;
                aProperties: PGREProperty;
                propertiesLength: PRUint32;
                buf: PAnsiChar; buflen: PRUint32): nsresult;
{$ENDIF}

function NS_CompareVersions(lhs, rhs: PAnsiChar): PRInt32;

function XPCOMGlueStartup(xpcomFile: PAnsiChar): nsresult;
function XPCOMGlueShutdown: nsresult;
function XPCOMGlueLoadXULFunctions(aSymbols: PDynamicFunctionLoad): nsresult;

function GRE_Startup: nsresult;
function GRE_Shutdown: nsresult;


// PChar functions
function NS_StrLen(const Str: PAnsiChar): Cardinal; overload;
function NS_StrCopy(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar; overload;
function NS_StrLCopy(Dest: PAnsiChar; const Source: PAnsiChar; maxLen: Cardinal): PAnsiChar; overload;
function NS_StrCat(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar; overload;
function NS_StrLCat(Dest: PAnsiChar; const Source: PAnsiChar; maxLen: Cardinal): PAnsiChar; overload;
function NS_StrComp(const Str1, Str2: PAnsiChar): Integer; overload;
function NS_StrRScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar; overload;

function NS_StrLen(const Str: PWideChar): Cardinal; overload;
function NS_StrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar; overload;
function NS_StrLCopy(Dest: PWideChar; const Source: PWideChar; maxLen: Cardinal): PWideChar; overload;
function NS_StrCat(Dest: PWideChar; const Source: PWideChar): PWideChar; overload;
function NS_StrLCat(Dest: PWideChar; const Source: PWideChar; maxLen: Cardinal): PWideChar; overload;
function NS_StrComp(const Str1, Str2: PWideChar): Integer; overload;
function NS_StrRScan(const Str: PWideChar; Chr: WideChar): PWideChar; overload;

function NS_CurrentProcessDirectory(buf: PAnsiChar; bufLen: Cardinal): Boolean;

type
  TAnsiCharArray = array [0..High(Word) div SizeOf(AnsiChar)] of AnsiChar;
  TMaxPathChar = array[0..MAX_PATH] of AnsiChar;
//  HINST = TLibHandle;
  PDependentLib = ^TDependentLib;
  TDependentLib = record
    libHandle: HMODULE;
    next: PDependentLib;
  end;


type
  nsIDirectoryServiceProvider_stdcall = interface(nsISupports)
  ['{bbf8cab0-d43a-11d3-8cc2-00609792278c}']
    function GetFile(const prop: PAnsiChar; out persistent: PRBool; out AFile: nsIFile): nsresult; stdcall;
  end;

  nsGREDirServiceProvider = class(TInterfacedObject,
                                  nsIDirectoryServiceProvider_stdcall)
  public
    FPathEnvString: TMaxPathChar;
    class function NewInstance: TObject; override;
    procedure FreeInstance; override;
    function GetFile(const prop: PAnsiChar; out persistent: PRBool; out AFile: nsIFile): nsresult; stdcall;
    function GetGreDirectory(out AFile: nsILocalFile): nsresult;
  end;

procedure ZeroArray(out AArray; const ASize: SizeInt);


implementation

uses
  {$IFDEF MSWINDOWS} Windows, {$ELSE} DynLibs, {$ENDIF} nsError, nsMemory;

type
  XPCOMExitRoutine = function : Longword; stdcall;

  InitFunc = function(out servMgr: nsIServiceManager; binDir: nsIFile; provider: nsIDirectoryServiceProvider): Longword; cdecl;
  ShutdownFunc = function (servMgr: nsIServiceManager): Longword; cdecl;
  GetServiceManagerFunc = function (out servMgr: nsIServiceManager): Longword; cdecl;
  GetComponentManagerFunc = function (out compMgr: nsIComponentManager): Longword; cdecl;
  GetComponentRegistrarFunc = function (out compReg: nsIComponentRegistrar): Longword; cdecl;
  GetMemoryManagerFunc = function (out memMgr: nsIMemory): Longword; cdecl;
  NewLocalFileFunc = function (const path: nsAString; followLinks: LongBool; out newFile: nsILocalFile): Longword; cdecl;
  NewNativeLocalFileFunc = function (const path: nsACString; followLinks: LongBool; out newFile: nsILocalFile): Longword; cdecl;
  RegisterXPCOMExitRoutineFunc = function (exitRoutine: XPCOMExitRoutine; proproty: Longword): Longword; cdecl;
  UnregisterXPCOMExitRoutineFunc = function (exitRoutine: XPCOMExitRoutine): Longword; cdecl;
  // Added for Gecko 1.8
  AllocFunc = function (size: PRSize): Pointer; cdecl;
  ReallocFunc = function (ptr: Pointer; size: PRSize): Pointer; cdecl;
  FreeFunc = procedure (ptr: Pointer); cdecl;
  Init3Func = function (out servMgr: nsIServiceManager; binDir: nsIFile; provider: nsIDirectoryServiceProvider; var staticComponents: nsStaticModuleInfoArray; componentCount: PRUint32): nsresult; cdecl;

  GetDebugFunc = function (out debug: nsIDebug): Longword; cdecl;
  GetTraceRefcntFunc = function (out traceRefcnt: nsITraceRefcnt): Longword; cdecl;
  // Added for Gecko 1.9
  DebugBreakFunc = procedure (aSeverity: PRUint32; aStr: PAnsiChar; aExpr: PAnsiChar; aFile: PAnsiChar; aLine: PRUint32); cdecl;
  XPCOMVoidFunc = procedure (); cdecl;
  LogAddRefFunc = procedure (var aPtr; refcnt: nsrefcnt; name: PAnsiChar; count: PRUint32); cdecl;
  LogReleaseFunc = procedure (var aPtr; refcnt: nsrefcnt; name: PAnsiChar); cdecl;
  LogCtorFunc = procedure (var aPtr; name: PAnsiChar; ident: PRUint32); cdecl;
  LogCOMPtrFunc = procedure (var aPtr; aIntf: nsISupports); cdecl;
  GetXPTCallStubFunc = function (const guid: TGUID; proxy: nsIXPTCProxy; out aIntf): nsresult; cdecl;
  DestroyXPTCallStubFunc = procedure (aStub: nsISupports); cdecl;
  InvokeByIndexFunc = function (aStub: nsISupports; methodIndex: PRUint32; paramCount: PRUint32; params: PXPTCVariantArray): nsresult; cdecl;
  CycleCollectorFunc = function (aStub: nsISupports): PRBool; cdecl;

  StringContainerInitFunc = function (var container: nsStringContainer): Longword; cdecl;
  StringContainerFinishFunc = procedure (var container: nsStringContainer); cdecl;
  StringGetDataFunc = function (const str: nsAString; out data: PWideChar; aTerminated: PLongBool): Longword; cdecl;
  StringCloneDataFunc = function (const str: nsAString): PWideChar; cdecl;
  StringSetDataFunc = procedure (str: nsAString; const data: PWideChar; length: Longword); cdecl;
  StringSetDataRangeFunc = procedure (str: nsAString; aCutOffset, aCutLength: Longword; const data: PWideChar; length: Longword); cdecl;
  StringCopyFunc = procedure (dst: nsAString; const src: nsAString); cdecl;
  // Added for Gecko 1.8
  StringContainerInit2Func = function (var container: nsStringContainer; const str: PWideChar; offset, length: PRUint32): nsresult; cdecl;
  StringGetMutableDataFunc = function (container: nsAString; aLength: PRUint32; out retval: PWideChar): PRUint32; cdecl;
  // Added for Gecko 1.9
  StringSetIsVoidFunc = procedure (dst: nsAString; const isVoid: PRBool); cdecl;
  StringGetIsVoidFunc = function (src: nsAString): PRBool; cdecl;

  CStringContainerInitFunc = function (var container: nsCStringContainer): Longword; cdecl;
  CStringContainerFinishFunc = procedure (var container: nsCStringContainer); cdecl;
  CStringGetDataFunc = function (const str: nsACString; out data: PAnsiChar; aTerminated: PLongBool): Longword; cdecl;
  CStringCloneDataFunc = function (const str: nsACString): PAnsiChar; cdecl;
  CStringSetDataFunc = procedure (str: nsACString; const data: PAnsiChar; length: Longword); cdecl;
  CStringSetDataRangeFunc = procedure (str: nsACString; aCutOffset, aCutLength: Longword; const data: PAnsiChar; length: Longword); cdecl;
  CStringCopyFunc = procedure (dst: nsACString; const src: nsACString); cdecl;
  // Added for Gecko 1.8
  CStringContainerInit2Func = function (var container: nsCStringContainer; const str: PAnsiChar; offset, length: PRUint32): nsresult; cdecl;
  CStringGetMutableDataFunc = function (container: nsACString; aLength: PRUint32; out retval: PAnsiChar): PRUint32; cdecl;
  // Added for Gecko 1.9
  CStringSetIsVoidFunc = procedure (dst: nsACString; const isVoid: PRBool); cdecl;
  CStringGetIsVoidFunc = function (src: nsACString): PRBool; cdecl;

  CStringToUTF16Func = function (const src: nsACString; encoding: nsSourceEncoding; dst: nsAString): Longword; cdecl;
  UTF16ToCStringFunc = function (const src: nsAString; encoding: nsSourceEncoding; dst: nsACString): Longword; cdecl;

  XPCOMFunctions = record
    version: Longword;
    size: Longword;

    init: InitFunc;
    shutdown: ShutdownFunc;
    getServiceManager: GetServiceManagerFunc;
    getComponentManager: GetComponentManagerFunc;
    getComponentRegistrar: GetComponentRegistrarFunc;
    getMemoryManager: GetMemoryManagerFunc;
    newLocalFile: NewLocalFileFunc;
    newNativeLocalFile: NewNativeLocalFileFunc;

    registerXPCOMExitRoutine: RegisterXPCOMExitRoutineFunc;
    unregisterXPCOMExitRoutine: UnregisterXPCOMExitRoutineFunc;

    // Added for Gecko 1.5
    getDebug: GetDebugFunc;
    getTraceRefCnt: GetTraceRefCntFunc;

    // Added for Gecko 1.7
    stringContainerInit: StringContainerInitFunc;
    stringContainerFinish: StringContainerFinishFunc;
    stringGetData: StringGetDataFunc;
    stringSetData: StringSetDataFunc;
    stringSetDataRange: StringSetDataRangeFunc;
    stringCopy: StringCopyFunc;
    cstringContainerInit: CStringContainerInitFunc;
    cstringContainerFinish: CStringContainerFinishFunc;
    cstringGetData: CStringGetDataFunc;
    cstringSetData: CStringSetDataFunc;
    cstringSetDataRange: CStringSetDataRangeFunc;
    cstringCopy: CStringCopyFunc;
    cstringToUTF16: CStringToUTF16Func;
    UTF16ToCString: UTF16ToCStringFunc;
    stringCloneData: StringCloneDataFunc;
    cstringCloneData: CStringCloneDataFunc;

    // Added for Gecko 1.8
    alloc: AllocFunc;
    realloc: ReallocFunc;
    free: FreeFunc;
    stringContainerInit2: StringContainerInit2Func;
    cstringContainerInit2: CStringContainerInit2Func;
    stringGetMutableData: StringGetMutableDataFunc;
    cstringGetMutableData: CStringGetMutableDataFunc;
    init3: Init3Func;

    // Added for Gecko 1.9
    debugBreak: DebugBreakFunc;
    logInit: xpcomVoidFunc;
    logTerm: xpcomVoidFunc;
    logAddRef: LogAddRefFunc;
    logRelease: LogReleaseFunc;
    logCtor: LogCtorFunc;
    logDtor: LogCtorFunc;
    logCOMPtrAddRef: LogCOMPtrFunc;
    logCOMPtrRelease: LogCOMPtrFunc;
    getXPTCallStub: GetXPTCallStubFunc;
    destroyXPTCallStub: DestroyXPTCallStubFunc;
    invokeByIndex: InvokeByIndexFunc;
    cycleSuspect: CycleCollectorFunc;
    cycleForget: CycleCollectorFunc;
    stringSetIsVoid: StringSetIsVoidFunc;
    stringGetIsVoid: StringGetIsVoidFunc;
    cstringSetIsVoid: CStringSetIsVoidFunc;
    cstringGetIsVoid: CStringGetIsVoidFunc;
  end;

  GetFrozenFunctionsFunc = function(out enrtyPoints: XPCOMFunctions; libraryPath: PAnsiChar): Longword; cdecl;

var
  xpcomFunc: XPCOMFunctions;

function NS_InitXPCOM2(out servMgr: nsIServiceManager;
                       binDir: nsIFile;
                       appFileLocationProvider: nsIDirectoryServiceProvider): nsresult;
begin
  if Assigned(xpcomFunc.init) then
    Result := xpcomFunc.init(servMgr, binDir, appFileLocationProvider)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_ShutdownXPCOM(servMgr: nsIServiceManager): nsresult;
begin
  if Assigned(xpcomFunc.shutdown) then
    Result := xpcomFunc.shutdown(servMgr)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetServiceManager(out servMgr: nsIServiceManager): nsresult;
begin
  if Assigned(xpcomFunc.getServiceManager) then
    Result := xpcomFunc.getServiceManager(servMgr)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetComponentManager(out compMgr: nsIComponentManager): nsresult;
begin
  if Assigned(xpcomFunc.getComponentManager) then
    Result := xpcomFunc.getComponentManager(compMgr)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetComponentRegistrar(out compReg: nsIComponentRegistrar): nsresult;
begin
  if Assigned(xpcomFunc.getComponentRegistrar) then
    Result := xpcomFunc.getComponentRegistrar(compReg)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetMemoryManager(out memMgr: nsIMemory): nsresult;
begin
  if Assigned(xpcomFunc.getMemoryManager) then
    Result := xpcomFunc.getMemoryManager(memMgr)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_NewLocalFile(const path: nsAString;
                         followLinks: PRBool;
                         out newFile: nsILocalFile): nsresult;
begin
  if Assigned(xpcomFunc.newLocalFile) then
    Result := xpcomFunc.newLocalFile(path, followLinks, newFile)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_NewNativeLocalFile(const path: nsACString;
                               followLinks: PRBool;
                               out newFile: nsILocalFile): nsresult;
begin
  if Assigned(xpcomFunc.newNativeLocalFile) then
    Result := xpcomFunc.newNativeLocalFile(path, followLinks, newFile)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_RegisterXPCOMExitRoutine(exitRoutine: XPCOMExitRoutine;
                                     priority: Longword): nsresult;
begin
  if Assigned(xpcomFunc.registerXPCOMExitRoutine) then
    Result := xpcomFunc.registerXPCOMExitRoutine(exitRoutine, priority)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_UnregisterXPCOMExitRoutine(exitRoutine: XPCOMExitRoutine): nsresult;
begin
  if Assigned(xpcomFunc.unregisterXPCOMExitRoutine) then
    Result := xpcomFunc.unregisterXPCOMExitRoutine(exitRoutine)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetDebug(out debug: nsIDebug): nsresult;
begin
  if Assigned(xpcomFunc.getDebug) then
    Result := xpcomFunc.getDebug(debug)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_GetTraceRefcnt(out traceRefcnt: nsITraceRefcnt): nsresult;
begin
  if Assigned(xpcomFunc.getTraceRefCnt) then
    Result := xpcomFunc.getTraceRefCnt(traceRefcnt)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_StringContainerInit(var aContainer: nsStringContainer): nsresult;
begin
  if Assigned(xpcomFunc.stringContainerInit) then
    Result := xpcomFunc.stringContainerInit(aContainer)
  else
    Result := NS_ERROR_FAILURE;
end;

procedure NS_StringContainerFinish(var aContainer: nsStringContainer);
begin
  if Assigned(xpcomFunc.stringContainerFinish) then
    xpcomFunc.stringContainerFinish(aContainer);
end;

function NS_StringGetData(const aStr: nsAString; out aData: PWideChar; aTerminated: PLongBool): nsresult;
begin
  if Assigned(xpcomFunc.stringGetData) then
    Result := xpcomFunc.stringGetData(aStr, aData, aTerminated)
  else
    Result := 0;
end;

procedure NS_StringSetData(aStr: nsAString; const aData: PWideChar; aDataLength: Longword);
begin
  if Assigned(xpcomFunc.stringSetData) then
    xpcomFunc.stringSetData(aStr, aData, aDataLength);
end;

procedure NS_StringSetDataRange(aStr: nsAString; aCutOffset, aCutLength: Longword; const aData: PWideChar; aDataLength: Longword);
begin
  if Assigned(xpcomFunc.stringSetDataRange) then
    xpcomFunc.stringSetDataRange(aStr, aCutOffset, aCutLength, aData, aDataLength);
end;

procedure NS_StringCopy(aDestStr: nsAString; const aSrcStr: nsAString);
begin
  if Assigned(xpcomFunc.stringCopy) then
    xpcomFunc.stringCopy(aDestStr, aSrcStr);
end;

procedure NS_StringAppendData(aStr: nsAString; const aData: PWideChar; aDataLength: Longword);
begin
  NS_StringSetDataRange(aStr, High(Longword), 0, aData, aDataLength);
end;

procedure NS_StringInsertData(aStr: nsAString; aOffSet: Longword; const aData: PWideChar; aDataLength: Longword);
begin
  NS_StringSetDataRange(aStr, aOffset, 0, aData, aDataLength);
end;

procedure NS_StringCutData(aStr: nsAString; aCutOffset, aCutLength: Longword);
begin
  NS_StringSetDataRange(aStr, aCutOffset, aCutLength, nil, 0);
end;

function NS_CStringContainerInit(var aContainer: nsCStringContainer): nsresult;
begin
  if Assigned(xpcomFunc.cstringContainerInit) then
    Result := xpcomFunc.cstringContainerInit(aContainer)
  else
    Result := NS_ERROR_FAILURE;
end;

procedure NS_CStringContainerFinish(var aContainer: nsCStringContainer);
begin
  if Assigned(xpcomFunc.cstringContainerFinish) then
    xpcomFunc.cstringContainerFinish(aContainer);
end;

function NS_CStringGetData(const aStr: nsACString; out aData: PAnsiChar; aTerminated: PLongBool): Longword;
begin
  if Assigned(xpcomFunc.cstringGetData) then
    Result := xpcomFunc.cstringGetData(aStr, aData, aTerminated)
  else
    Result := 0;
end;

procedure NS_CStringSetData(aStr: nsACString; const aData: PAnsiChar; aDataLength: Longword);
begin
  if Assigned(xpcomFunc.cstringSetData) then
    xpcomFunc.cstringSetData(aStr, aData, aDataLength);
end;

procedure NS_CStringSetDataRange(aStr: nsACString; aCutOffset, aCutLength: Longword; const aData: PAnsiChar; aDataLength: Longword);
begin
  if Assigned(xpcomFunc.cstringSetDataRange) then
    xpcomFunc.cstringSetDataRange(aStr, aCutOffset, aCutLength, aData, aDataLength);
end;

procedure NS_CStringCopy(aDestStr: nsACString; const aSrcStr: nsACString);
begin
  if Assigned(xpcomFunc.cstringCopy) then
    xpcomFunc.cstringCopy(aDestStr, aSrcStr);
end;

procedure NS_CStringAppendData(aStr: nsACString; const aData: PAnsiChar; aDataLength: Longword);
begin
  NS_CStringSetDataRange(aStr, High(Longword), 0, aData, aDataLength);
end;

procedure NS_CStringInsertData(aStr: nsACString; aOffSet: Longword; const aData: PAnsiChar; aDataLength: Longword);
begin
  NS_CStringSetDataRange(aStr, aOffset, 0, aData, aDataLength);
end;

procedure NS_CStringCutData(aStr: nsACString; aCutOffset, aCutLength: Longword);
begin
  NS_CStringSetDataRange(aStr, aCutOffset, aCutLength, nil, 0);
end;

function NS_CStringToUTF16(const aSource: nsACString; aSrcEncoding: nsSourceEncoding; aDest: nsAString): nsresult;
begin
  if Assigned(xpcomFunc.cstringToUTF16) then
    Result := xpcomFunc.cstringToUTF16(aSource, aSrcEncoding, aDest)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_UTF16ToCString(const aSource: nsAString; aSrcEncoding: nsSourceEncoding; aDest: nsACString): nsresult;
begin
  if Assigned(xpcomFunc.UTF16ToCString) then
    Result := xpcomFunc.UTF16ToCString(aSource, aSrcEncoding, aDest)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_StringCloneData(const aStr: nsAString): PWideChar;
begin
  if Assigned(xpcomFunc.stringCloneData) then
    Result := xpcomFunc.stringCloneData(aStr)
  else
    Result := nil;
end;

function NS_CStringCloneData(const aStr: nsACString): PAnsiChar;
begin
  if Assigned(xpcomFunc.cstringCloneData) then
    Result := xpcomFunc.cstringCloneData(aStr)
  else
    Result := nil;
end;

// Added for Gecko 1.8
function NS_Alloc(size: PRSize): Pointer; cdecl;
begin
  if Assigned(xpcomFunc.alloc) then
    Result := xpcomFunc.alloc(size)
  else
    Result := nil;
end;

function NS_Realloc(ptr: Pointer; size: PRSize): Pointer; cdecl;
begin
  if Assigned(xpcomFunc.realloc) then
    Result := xpcomFunc.realloc(ptr, size)
  else
    Result := nil;
end;

procedure NS_Free(ptr: Pointer); cdecl;
begin
  if Assigned(xpcomFunc.free) then
    xpcomFunc.free(ptr);
end;

function NS_InitXPCOM3(out servMgr: nsIServiceManager; binDir: nsIFile; appFileLocationProvider: nsIDirectoryServiceProvider; var staticComponents: nsStaticModuleInfoArray; componentCount: PRUint32): nsresult; cdecl;
//FPC port: added const to staticComponents and changed componentCount from
// PRInt32 to PRUInt32 so they match init3 - wouldn't assemble otherwise on PowerPC.
begin
  if Assigned(xpcomFunc.init3) then
    Result := xpcomFunc.init3(servMgr, binDir, appFileLocationProvider, staticComponents, componentCount)
  else
    Result := NS_ERROR_FAILURE;
end;

function NS_StringContainerInit2(var aContainer: nsStringContainer; const aStr: PWideChar; aOffset, aLength: PRUint32): nsresult; cdecl;
begin
  if Assigned(xpcomFunc.stringContainerInit2) then
    Result := xpcomFunc.stringContainerInit2(aContainer, aStr, aOffset, aLength)
  else
    Result := NS_ERROR_FAILURE;
end;

procedure NS_StringSetIsVoid(aStr: nsAString; const aIsVoid: PRBool); cdecl;
begin
  if Assigned(xpcomFunc.stringSetIsVoid) then
    xpcomFunc.stringSetIsVoid(aStr, aIsVoid);
end;

function NS_StringGetIsVoid(const aStr: nsAString): PRBool; cdecl;
begin
  if Assigned(xpcomFunc.stringGetIsVoid) then
    Result := xpcomFunc.stringGetIsVoid(aStr)
  else
    Result := false;
end;

function NS_CStringContainerInit2(var aContainer: nsCStringContainer; const aStr: PAnsiChar; aOffset, aLength: PRUint32): nsresult; cdecl;
begin
  if Assigned(xpcomFunc.cstringContainerInit2) then
    Result := xpcomFunc.cstringContainerInit2(aContainer, aStr, aOffset, aLength)
  else
    Result := NS_ERROR_FAILURE;
end;

procedure NS_CStringSetIsVoid(aStr: nsACString; const aIsVoid: PRBool); cdecl;
begin
  if Assigned(xpcomFunc.cstringSetIsVoid) then
    xpcomFunc.cstringSetIsVoid(aStr, aIsVoid);
end;

function NS_CStringGetIsVoid(const aStr: nsACString): PRBool; cdecl;
begin
  if Assigned(xpcomFunc.cstringGetIsVoid) then
    Result := xpcomFunc.cstringGetIsVoid(aStr)
  else
    Result := false;
end;

// Added for Gecko 1.9
procedure NS_DebugBreak(aSeverity: PRUint32; aStr: PAnsiChar; aExpr: PAnsiChar; aFile: PAnsiChar; aLine: PRUint32); cdecl;
begin
  if Assigned(xpcomFunc.debugBreak) then
    xpcomFunc.debugBreak(aSeverity, aStr, aExpr, aFile, aLine);
end;

procedure NS_LogInit(); cdecl;
begin
  if Assigned(xpcomFunc.logInit) then
    xpcomFunc.logInit;
end;

procedure NS_LogTerm(); cdecl;
begin
  if Assigned(xpcomFunc.logTerm) then
    xpcomFunc.logTerm;
end;

procedure NS_LogAddRef(aPtr: Pointer; aNewRefCnt: nsrefcnt; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
begin
  if Assigned(xpcomFunc.logAddRef) then
    xpcomFunc.logAddRef(aPtr, aNewRefCnt, aTypeName, aInstanceSize);
end;

procedure NS_LogRelease(aPtr: Pointer; aNewRefCnt: nsrefcnt; aTypeName: PAnsiChar); cdecl;
begin
  if Assigned(xpcomFunc.logRelease) then
    xpcomFunc.logRelease(aPtr, aNewRefCnt, aTypeName);
end;

procedure NS_LogCtor(aPtr: Pointer; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
begin
  if Assigned(xpcomFunc.logCtor) then
    xpcomFunc.logCtor(aPtr, aTypeName, aInstanceSize);
end;

procedure NS_LogDtor(aPtr: Pointer; aTypeName: PAnsiChar; aInstanceSize: PRUint32); cdecl;
begin
  if Assigned(xpcomFunc.logDtor) then
    xpcomFunc.logDtor(aPtr, aTypeName, aInstanceSize);
end;

procedure NS_LogCOMPtrAddRef(aCOMPtr: Pointer; aObject: nsISupports); cdecl;
begin
  if Assigned(xpcomFunc.logCOMPtrAddRef) then
    xpcomFunc.logCOMPtrAddRef(aCOMPtr, aObject);
end;

procedure NS_LogCOMPtrRelease(aCOMPtr: Pointer; aObject: nsISupports); cdecl;
begin
  if Assigned(xpcomFunc.logCOMPtrRelease) then
    xpcomFunc.logCOMPtrRelease(aCOMPtr, aObject);
end;


function NS_GetXPTCallStub(aIID: TGUID; aOuter: nsIXPTCProxy; out aStub): nsresult; cdecl;
begin
  if Assigned(xpcomFunc.getXPTCallStub) then
    Result := xpcomFunc.getXPTCallStub(aIID, aOuter, aStub)
  else
    Result := NS_ERROR_FAILURE;
end;

procedure NS_DestroyXPTCallStub(aStub: nsISupports); cdecl;
begin
  if Assigned(xpcomFunc.destroyXPTCallStub) then
    xpcomFunc.destroyXPTCallStub(aStub);
end;

function NS_InvokeByIndex(that: nsISupports; methodIndex: PRUint32; paramCount: PRUint32; params: PXPTCVariantArray): nsresult; cdecl;
begin
  if Assigned(xpcomFunc.invokeByIndex) then
    Result := xpcomFunc.invokeByIndex(that, methodIndex, paramCount, params)
  else
    Result := NS_ERROR_FAILURE;
end;

function CheckVersion(toCheck: PAnsiChar;
                      const versions: PGREVersionRangeArray;
                      versionsLength: PRUint32): PRBool; forward;

{$IFDEF MSWINDOWS}
function GRE_GetPathFromRegKey(
                aRegKey: HKEY;
                versions: PGREVersionRangeArray;
                versionsLength: PRUint32;
                properties: PGREPropertyArray;
                propertiesLength: PRUint32;
                buf: PAnsiChar; buflen: PRUint32): PRBool; forward;
{$ENDIF}

function GRE_GetGREPathWithProperties(
                aVersions: PGREVersionRange;
                versionsLength: PRUint32;
                aProperties: PGREProperty;
                propertiesLength: PRUint32;
                buf: PAnsiChar; buflen: PRUint32): nsresult;
var
  env: string;
  hRegKey: HKEY;
  ok: PRBool;
  versions: PGREVersionRangeArray;
  properties: PGREPropertyArray;
  GeckoVersion: String;
  function GRE_FireFox(): string;
  var
    Reg: TRegistry;
    FF: string;
  begin
    Reg:=TRegistry.Create(KEY_ALL_ACCESS);
    Reg.RootKey:=HKEY_LOCAL_MACHINE;
    if Reg.OpenKeyReadOnly(GRE_FIREFOX_BASE_WIN_REG_LOC) then begin
      FF:=Reg.ReadString('CurrentVersion');
      FF:=LeftStr(FF,Pos(' ',FF)-1);
      Reg.CloseKey;
      FF:=format('%s %s',[GRE_FIREFOX_BASE_WIN_REG_LOC,FF]);
      if Reg.OpenKeyReadOnly(FF) then begin
        GeckoVersion:=Reg.ReadString('GeckoVer');
        if GeckoVersion<>'' then begin
          Reg.CloseKey;
          FF:=FF+'\bin';
          if Reg.OpenKeyReadOnly(FF) then begin
            Result:=Reg.ReadString('PathToExe');
            Result:=ExtractFilePath(Result)+XPCOM_DLL;
          end;
        end;
      end;
    end;
    Reg.CloseKey;
    Reg.Free;
  end;
begin
  versions := PGREVersionRangeArray(aVersions);
  properties := PGREPropertyArray(aProperties);
(*
  env := GetEnvironmentVariable('GRE_HOME');
  if Assigned(env) and (env[0] <>#0) then
  begin
    p[0] := #0;
    safe_strncat(p, env, MAX_PATH);
    safe_strncat(p, '\xpcom.dll', MAX_PATH);

  end;
  *)

  env:=sysutils.GetEnvironmentVariable('USE_LOCAL_GRE');
  if env<>''then
  begin
    strlcopy(Buf,pchar(env+PathDelim+XPCOM_DLL),buflen);
    Result := NS_OK;
    Exit;
  end;

  {$IFDEF MSWINDOWS}
  //Check for default mozilla GRE
  hRegKey := 0;
  if RegOpenKeyEx(HKEY_CURRENT_USER, GRE_MOZILLA_WIN_REG_LOC, 0,
                  KEY_READ, hRegKey) = ERROR_SUCCESS then
  begin
    ok := GRE_GetPathFromRegKey(hRegkey,
                                versions, versionsLength,
                                properties, propertiesLength,
                                buf, buflen);
    RegCloseKey(hRegKey);
    if ok then
    begin
      Result := NS_OK;
      Exit;
    end;
  end;

  if RegOpenKeyEx(HKEY_LOCAL_MACHINE, GRE_MOZILLA_WIN_REG_LOC, 0,
                  KEY_READ, hRegKey) = ERROR_SUCCESS then
  begin
    ok := GRE_GetPathFromRegKey(hRegKey,
                                versions, versionsLength,
                                properties, propertiesLength,
                                buf, buflen);
    RegCloseKey(hRegKey);
    if ok then
    begin
      Result := NS_OK;
      Exit;
    end;
  end;
  //Check for Firefox GRE
  (*GrePath:=GRE_FireFox();
  if GrePath<>'' then begin
    strlcopy(buf,pchar(GrePath),bufLen);
    Result:=NS_OK;
    exit;
  end;*)
  {$ENDIF}
  Result := NS_ERROR_FAILURE;
end;

function CheckVersion(toCheck: PAnsiChar;
                      const versions: PGREVersionRangeArray;
                      versionsLength: PRUint32): PRBool;
var
  i: DWORD;
  c: PRInt32;
begin
  Result := True;
  if versionsLength=0 then
    Exit;
  for i:=0 to versionsLength-1 do
  begin
    c := NS_CompareVersions(toCheck, versions[i].lower);
    if c < 0 then
      Continue;

    if (c=0) and not versions[i].lowerInclusive then
      Continue;

    c := NS_CompareVersions(toCheck, versions[i].upper);
    if c > 0 then
      Continue;

    if (c=0) and not versions[i].upperInclusive then
      Continue;

    Exit;
  end;
  Result := False;
end;

{$IFDEF MSWINDOWS}
function CopyWithEnvExpansion(
                aDest: PAnsiChar;
                aSource: PAnsiChar;
                aBufLen: PRUint32;
                aType: DWORD): PRBool;
begin
  Result := False;
  case aType of
  REG_SZ:
    begin
      if NS_StrLen(aSource)>=aBufLen then
        Exit;
      NS_StrCopy(aDest, aSource);
      Result := True;
    end;
  REG_EXPAND_SZ:
    begin
      if ExpandEnvironmentStringsA(aSource, aDest, aBufLen) <= aBufLen then
        Result := True;
    end;
  end;
end;

function GRE_GetPathFromRegKey(
                aRegKey: HKEY;
                versions: PGREVersionRangeArray;
                versionsLength: PRUint32;
                properties: PGREPropertyArray;
                propertiesLength: PRUint32;
                buf: PAnsiChar; buflen: PRUint32): PRBool;
var
  i, j: DWORD;
  name: array [0..MAX_PATH] of AnsiChar;
  nameLen: DWORD;
  subKey: HKEY;
  ver: array[0..40] of AnsiChar;
  verLen: DWORD;
  ok: PRBool;
  propbuf: array[0..MAX_PATH] of AnsiChar;
  proplen: DWORD;
  pathtype: DWORD;
begin
  i := 0;
  while True do
  begin
    nameLen := MAX_PATH;
    if RegEnumKeyExA(aRegKey, i, PAnsiChar(@name), nameLen, nil, nil, nil, nil) <>
       ERROR_SUCCESS then
    begin
      break;
    end;

    subKey := 0;
    if RegOpenKeyExA(aRegKey, name, 0, KEY_QUERY_VALUE, subKey) <>
       ERROR_SUCCESS then
    begin
      Continue;
    end;

    ok := False;
    verLen := SizeOf(ver) div SizeOf(ver[0]);
    if (RegQueryValueExA(subKey, 'Version', nil, nil,
                        PByte(@ver), @VerLen)=ERROR_SUCCESS) and
        CheckVersion(ver, versions, versionsLength) then
    begin
      ok := True;
      if propertiesLength>0 then
      begin
        for j:=0 to propertiesLength-1 do
        begin
          proplen := Sizeof(propbuf);
          if (RegQueryValueExA(subKey, properties[i].property_, nil, nil,
              PByte(@propbuf), @proplen)<>ERROR_SUCCESS) or
              (NS_StrComp(propbuf, properties[i].value)<>0) then
          begin
            ok := False;
          end;
        end;
      end;

      proplen := SizeOf(propbuf);
      if ok and
        ((RegQueryValueExA(subKey, 'GreHome', nil, @pathtype,
                          PByte(@propbuf), @proplen)<>ERROR_SUCCESS) or
         (propbuf[0] = #0) or
         not CopyWithEnvExpansion(Buf, propbuf, BufLen, pathtype)) then
      begin
        ok := False;
      end else
      begin
        NS_StrLCat(Buf, '\'+XPCOM_DLL, BufLen);
      end;
    end;
    RegCloseKey(subKey);
    if ok then
    begin
      Result := ok;
      Exit;
    end;
    Inc(i);
  end;
  buf[0] := #0;
  Result := false;
end;
{$ENDIF}

var
  sDependentLibs: PDependentLib = nil;
  sXULLibrary: HINST = 0;

type
  TDependentLibsCallback = procedure (aDependentLib: PAnsiChar);

function XPCOMGlueLoad(xpcomFile: PAnsiChar): GetFrozenFunctionsFunc; forward;
procedure XPCOMGlueUnload(); forward;
function fullpath(absPath, relPath: PAnsiChar; maxLength: PRUint32): PAnsiChar; forward;

const
  BUFFEREDFILE_BUFSIZE = 256;
type
  TBufferedFile = record
    fs: TFileStream;
    buf: array [0..BUFFEREDFILE_BUFSIZE-1] of AnsiChar;
    bufPos: Integer;
    bufMax: Integer;
  end;

function BufferedFile_Open(name: PAnsiChar; out ret: TBufferedFile): Boolean;
begin
  try
    ret.fs:=TFileStream.Create(name,fmOpenRead, fmShareDenyWrite);
    result:=true;
    ret.bufPos := 0;
    ret.bufMax := -1;
  except
    ret.fs:=nil;
  end;
end;

procedure BufferedFile_Close(var aFile: TBufferedFile);
begin
  afile.fs.Free;
  afile.fs:=nil;
  aFile.bufPos := 0;
  aFile.bufMax := -1;
end;

procedure BufferedFile_ReadBuffer(var aFile: TBufferedFile);
var
  readSize: DWORD;
begin
  readSize:=aFile.fs.Read(aFile.buf, BUFFEREDFILE_BUFSIZE);
  begin
    aFile.bufPos := 0;
    aFile.bufMax := readSize;
  end;
end;

function BufferedFile_GetString(dest: PAnsiChar; destSize: PRUint32; var buf: TBufferedFile): PRInt32;
var
  i: Cardinal;
  c: AnsiChar;
begin
  i := 0;
  c := #0;
  while (i<destSize-1) do
  begin
    if buf.bufpos>=buf.bufMax then
      BufferedFile_ReadBuffer(buf);
    if buf.bufPos>=buf.bufMax then
      Break;

    c := buf.buf[buf.bufPos];
    dest[i] := c;
    Inc(i);
    Inc(buf.bufPos);
    if (c=#13) or (c=#10) then
    begin
      dest[i] := #10;
      Break;
    end;
  end;
  if (c=#13) and (i<destSize-1) then
  begin
    if buf.bufpos>=buf.bufMax then
      BufferedFile_ReadBuffer(buf);
    if buf.bufPos<buf.bufMax then
    begin
      c := buf.buf[buf.bufPos];
      if c=#10 then
      begin
        Inc(i);
        Inc(buf.bufPos);
      end;
    end;
  end;
  dest[i] := #0;
  Result := i;
end;

procedure XPCOMGlueLoadDependentLibs(xpcomDir: PAnsiChar; cb: TDependentLibsCallback);
var
  buffer: TMaxPathChar;
  buffer2: TMaxPathChar;
  f: TBufferedFile;
  l: Cardinal;
const
  XPCOM_DEPENDENT_LIBS_LIST = 'dependentlibs.list';
begin
  NS_StrCopy(buffer, xpcomDir);
  NS_StrLCat(buffer, '\' + XPCOM_DEPENDENT_LIBS_LIST, MAX_PATH);

  if not BufferedFile_Open(buffer, f) then
  begin
    Exit;
  end;

  try
    while BufferedFile_GetString(buffer, MAX_PATH, f)>0 do
    begin
      l := NS_StrLen(buffer);
      if (buffer[0] = '#') or (l=0) then
        Continue;
      if buffer[l-1] in [#10, #13] then
        buffer[l-1]:= #0;
      NS_StrCopy(buffer2, xpcomdir);
      NS_StrLCat(buffer2, '\', MAX_PATH);
      NS_StrLCat(buffer2, buffer, MAX_PATH);

      cb(buffer2);
    end;
  finally
    BufferedFile_Close(f);
  end;
end;

procedure AppendDependentLib(libHandle: HINST);
var
  d: PDependentLib;
begin
  d := GetMemory(sizeof(TDependentLib));
  if not Assigned(d) then Exit;
  d.next := sDependentLibs;
  d.libHandle := libHandle;

  sDependentLibs := d;
end;

procedure ReadDependentCB(aDependentLib: PAnsiChar);
var
  h: HINST;
  OldDir: string;
  NewDir: string;
begin
  //Changes directory temporaly to resolve automatic modules loading
  //in a crossplatform way.
  OldDir:=GetCurrentDir;
  NewDir:=ExtractFilePath(aDependentLib);
  SetCurrentDir(NewDir);
  h := LoadLibrary(aDependentLib);
  SetCurrentDir(OldDir);
  if h <> 0 then
    AppendDependentLib(h)
  else
    Raise Exception.Create('Missing Gecko runtime library: '+aDependentLib);
end;

function XPCOMGlueLoad(xpcomFile: PAnsiChar): GetFrozenFunctionsFunc;
var
  xpcomDir: TMaxPathChar;
  idx: PRInt32;
  h: HINST;
begin
  if (xpcomFile[0]='.') and (xpcomFile[1]=#0) then
  begin
    xpcomFile := XPCOM_DLL;
  end else
  begin
    fullpath(xpcomDir, xpcomFile, sizeof(xpcomDir));
    idx := NS_StrLen(xpcomDir);
    while (idx>=0) and not (xpcomDir[idx] in ['\','/']) do Dec(idx);
    if idx>=0 then
    begin
      xpcomDir[idx] := #0;
      XPCOMGlueLoadDependentLibs(xpcomDir, ReadDependentCB);
      NS_StrLCat(xpcomdir, '\'+xul_dll, sizeof(xpcomdir));
      sXULLibrary := LoadLibrary(xpcomdir);
    end;
  end;

  h := LoadLibrary(xpcomFile);

  if h <> 0 then
    begin
    AppendDependentLib(h);
    Result := GetFrozenFunctionsFunc(GetProcAddress( h, 'NS_GetFrozenFunctions' ));
    end
  else
    Result := nil;

  if not Assigned(Result) then
    XPCOMGlueUnload();
end;

procedure XPCOMGlueUnload();
var
  tmp : PDependentLib;
begin
  while Assigned(sDependentLibs) do
  begin
    FreeLibrary(sDependentLibs.libHandle);
    tmp := sDependentLibs;
    sDependentLibs := sDependentLibs.next;
    FreeMemory(tmp);
  end;

  if sXULLibrary<>0 then
  begin
    FreeLibrary(sXULLibrary);
    sXULLibrary := 0;
  end;
end;

function XPCOMGlueStartup(xpcomFile: PAnsiChar): nsresult;
const
  XPCOM_GLUE_VERSION = 1;
var
  func: GetFrozenFunctionsFunc;
begin
  Result := NS_ERROR_FAILURE;

  xpcomFunc.version := XPCOM_GLUE_VERSION;
  xpcomFunc.size := SizeOf(XPCOMFunctions);

  if not Assigned(xpcomFile) then
    xpcomFile := XPCOM_DLL;

  func := XPCOMGlueLoad(xpcomFile);

  if not Assigned(func) then
    Exit;

  Result := func(xpcomFunc, xpcomFile);

  if NS_FAILED(Result) then
    XPCOMGlueUnload();
end;

function XPCOMGlueShutdown: nsresult;
begin
  XPCOMGlueUnload();

  FillChar(xpcomFunc, SizeOf(xpcomFunc), Byte(0));

  Result := NS_OK;
end;

function XPCOMGlueLoadXULFunctions(aSymbols: PDynamicFunctionLoad): nsresult;
var
  i: Integer;
  symbols: PDynamicFunctionLoadArray;
begin
  symbols := PDynamicFunctionLoadArray(aSymbols);

  if sXULLibrary=0 then
  begin
    Result := NS_ERROR_NOT_INITIALIZED;
    Exit;
  end;

  Result := NS_OK;
  i := 0;
  while Assigned(symbols[i].functionName) do
  begin

    PPointer(symbols[i].function_)^ :=
      GetProcAddress(sXULLibrary, symbols[i].functionName);
    if not Assigned(PPointer(symbols[i].function_)^) then
      Result := NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
    Inc(i);
  end;
end;

type
  TVersionPart = record
    numA: PRInt32;
    strB: PAnsiChar;
    strBLen: PRUint32;
    numC: PRInt32;
    extraD: PAnsiChar;
    extraDlen: PRUint32;
  end;

  TGREVersion = record
    versionStr: PAnsiChar;
    major: TVersionPart;
    minor: TVersionPart;
    revision: TVersionPart;
  end;

function IsNumber(AChar: AnsiChar): Boolean;
begin
  Result := AChar in ['0'..'9'];
end;

function GetGREVersion(verStr: PAnsiChar): TGREVersion;
const
  nullStr: PAnsiChar = '';
  pre = 'pre';
  preLen = Length(pre);
  preStr: PAnsiChar = pre;
var
  idx: Integer;
  workInt: Integer;
  vers: array[0..2] of TVersionPart;
  //verStrPtr: PAnsiCharArray;
  i, j: Integer;
  dot: Integer;
begin
  idx := 0;
  ZeroArray(vers, sizeof(vers));
  for i:=0 to 2 do
  begin
    dot := idx;
    while (verStr[dot]<>#0) and (verStr[dot]<>'.') do Inc(dot);

    if (dot-idx=1) and (verStr[idx]='*') then
    begin
      vers[i].numA := MaxInt;
      vers[i].strB := nullStr;
    end else
    begin
      workInt := 0;
      while IsNumber(verStr[idx]) do
      begin
        workInt := workInt * 10 + (Ord(verStr[idx]) - Ord('0'));
        Inc(idx);
      end;
      vers[i].numA := workInt;
      vers[i].strB := verStr+idx;
    end;

    if vers[i].strB[0]=#0 then
    begin
      vers[i].strB := nil;
      vers[i].strBlen := 0;
    end else
    if vers[i].strB[0]='+' then
    begin
      Inc(vers[i].numA);
      vers[i].strB := preStr;
      vers[i].strBlen := preLen;
    end else
    begin
      j := idx;
      while (j<dot) and not (verstr[j] in ['0'..'9', '+','-']) do Inc(j);
      vers[i].strBlen := j - idx;
      if (j < dot) then
      begin
        idx := j;
        workInt := 0;
        while IsNumber(verStr[idx]) do
        begin
          workInt := workInt * 10 + (Ord(verStr[idx])-Ord('0'));
          Inc(idx);
        end;
        vers[i].numC := workInt;
        vers[i].extraD := verStr + idx;
        vers[i].extraDlen := dot - idx;
      end;
    end;

    idx := dot;
    if verStr[idx] = #0 then
      Break;
    Inc(idx);
  end;

  Result.versionStr := verStr;
  Result.major := vers[0];
  Result.minor := vers[1];
  Result.revision := vers[2];
end;

function StrNNComp(lhs: PAnsiChar; lhsLen: PRUint32; rhs: PAnsiChar; rhsLen: PRUint32): PRInt32;
begin
  while (lhsLen>0) and (rhsLen>0) do
  begin
    Result := Ord(lhs[0]) - Ord(rhs[0]);
    if Result<>0 then Exit;
    Inc(lhs);
    Dec(lhsLen);
    Inc(rhs);
    Dec(rhsLen);
  end;
  Result := lhsLen - rhsLen;
end;

function GREVersionPartCompare(const lhs, rhs: TVersionPart): Integer;
begin
  Result := lhs.numA - rhs.numA;
  if Result<>0 then Exit;
  Result := strnncomp(lhs.strB, lhs.strBLen, rhs.strB, rhs.strBLen);
  if Result <>0 then Exit;
  Result := lhs.numC - rhs.numC;
  if Result<>0 then Exit;
  Result := strnncomp(lhs.extraD, lhs.extraDLen, rhs.extraD, rhs.extraDLen);
end;

function GREVersionCompare(const lhs, rhs: TGREVersion): Integer;
begin
  Result := GREVersionPartCompare(lhs.major, rhs.major);
  if Result<>0 then Exit;
  Result := GREVersionPartCompare(lhs.minor, rhs.minor);
  if Result<>0 then Exit;
  Result := GREVersionPartCompare(lhs.revision, rhs.revision);
end;

function NS_CompareVersions(lhs, rhs: PAnsiChar): PRInt32;
var
  lhsVer, rhsVer: TGREVersion;
begin
  lhsVer := GetGREVersion(lhs);
  rhsVer := GetGREVersion(rhs);
  Result := GREVersionCompare(lhsVer, rhsVer);
end;

{$IFDEF GECKO_EXPERIMENTAL}
// あるファイルがGREの必要バ[ジョンに達しているかを調べるB
function GetPathFromConfigDir(dirname: PAnsiChar; buf: PAnsiChar): Boolean;
begin
  //TODO 1: GetPathFromConfigDir の実装
  Result := False;
end;

function GetPathFromConfigFile(const filename: PAnsiChar; buf: PAnsiChar): Boolean;
begin
  //TODO 1: GetPathFromConfigFile の実装
  Result := False;
end;
{$ENDIF GECKO_EXPERIMENTAL}

function IsXpcomDll(const filename: PAnsiChar): Boolean;
var
  module: HMODULE;
  proc: Pointer;
begin
  Result := False;
  module := LoadLibraryA(filename);
  if module=0 then Exit;

  proc := GetProcAddress(module, 'NS_GetFrozenFunctions');
  if Assigned(proc) then Result := True;

  FreeLibrary(module);
end;

function CheckGeckoVersion(path: PAnsiChar; const reqVer: TGREVersion): Boolean;
const
  BUFSIZE = 4096;
var
  buf: array[0..BUFSIZE-1] of Char;
  fileVer: PAnsiChar;
  dwSize: DWORD;
  dw: DWORD;
  greVer: TGREVersion;
begin
  Result := False;
  dw:=1; //Non zero
  dwSize := GetFileVersionInfoSizeA(path, dw);
  if (dwSize<=0) or (dwSize>BUFSIZE) then Exit;

  Result := GetFileVersionInfoA(path, 0, dwSize, @buf);
  if not Result then Exit;

  // バ[ジョン﨣ﾌ言語IDは決め打ち
  fileVer:=nil;
  Result := VerQueryValueA(@buf, '\StringFileInfo\000004b0\FileVersion', Pointer(fileVer), dw);
  if not Result then Exit;

  greVer := GetGREVersion(fileVer);

  if GREVersionCompare(greVer, reqVer)>=0 then Result := True;
end;

function GetLatestGreFromReg(regBase: HKEY; const reqVer: TGREVersion;
  grePath: PAnsiChar; var greVer: TGREVersion): Boolean;
var
  curKey: HKEY = 0;
  dwSize: DWORD;
  i: Integer;
  keyName: TMaxPathChar;
  rv: HRESULT;
  path, dllPath: TMaxPathChar;
  ver: TGREVersion;
begin
  Result := False;
  i := 0;
  dwSize := MAX_PATH;
  rv := RegEnumKeyExA(regBase, i, keyName, dwSize, nil, nil, nil, nil);
  while rv=0 do
  begin
    rv := RegOpenKeyA(regBase, PAnsiChar(@keyName), curKey);
    if rv=0 then
    begin
      dwSize := MAX_PATH;
      rv := RegQueryValueExA(curKey, 'GreHome', nil, nil, PByte(@path), @dwSize);
      if rv=0 then
      begin
        ver := GetGREVersion(keyName);
        if (GREVersionCompare(ver, reqVer)>=0) and
           (GREVersionCompare(ver, greVer)>=0) then
        begin
          dllPath := path;
          NS_StrCat(dllPath, '\'+XPCOM_DLL);
          //if IsXpcomDll(dllPath) then
//          if CheckGeckoVersion(dllPath, reqVer) and
//             IsXpcomDll(@dllPath) then
          if CheckGeckoVersion(dllPath, reqVer) then
          begin
            NS_StrCopy(grePath, path);
            greVer := ver;
            Result := True;
          end;
        end;
      end;
      RegCloseKey(curKey);
    end;
    Inc(i);
    dwSize := MAX_PATH;
    rv := RegEnumKeyExA(regBase, i, keyName, dwSize, nil, nil, nil, nil);
  end;
  RegCloseKey(regBase);
end;

function GetLatestGreLocation(buf: PAnsiChar): Boolean;
const
  nameBase: PAnsiChar = 'Software\mozilla.org\GRE';
var
  rv: HRESULT;
  base: HKEY = 0;
  cuPath, lmPath: TMaxPathChar;
  cuVer, lmVer: TGREVersion;
  reqVer: TGREVersion;
  hasLM, hasCU: Boolean;
label
  NoLocalMachine,
  NoCurrentUser;
begin
  ZeroArray(cuVer, SizeOf(cuVer));
  ZeroArray(lmVer, SizeOf(lmVer));
  reqVer := GetGREVersion(GRE_BUILD_ID);

  rv := RegOpenKeyA(HKEY_LOCAL_MACHINE, nameBase, base);
  HasLM := (rv=ERROR_SUCCESS) and GetLatestGreFromReg(base, reqVer, lmPath, lmVer);
NoLocalMachine:;
  rv := RegOpenKeyA(HKEY_CURRENT_USER, nameBase, base);
  hasCU := (rv=ERROR_SUCCESS) and GetLatestGreFromReg(base, reqVer, cuPath, cuVer);
NoCurrentUser:;
  Result := hasLM or hasCU;

  if Result then
  begin
    if GREVersionCompare(lmVer,cuVer)>0 then
      //buf := lmPath
      NS_StrCopy(buf, lmPath)
    else
      //buf := cuPath;
      NS_StrCopy(buf, cuPath);
  end;
end;

var
  GRELocation: TMaxPathChar;

function GetGREDirectoryPath(buf: PAnsiChar): Boolean;
{$IFDEF MSWINDOWS}
//const
//  GRE_REGISTRY_KEY = GRE_MOZILLA_WIN_REG_LOC + GRE_BUILD_ID;
var
  cpd:TMaxPathChar;
  dllPath: TMaxPathChar;
  useLocalGre: TMaxPathChar;
begin
  if NS_StrLen(GreLocation)>0 then
  begin
    NS_StrCopy(buf, GreLocation);
    Result := True;
    Exit;
  end;

  if NS_CurrentProcessDirectory(cpd, MAX_PATH) then
  begin
    dllPath := cpd;
    NS_StrCat(dllPath, '\'+XPCOM_DLL);
    if IsXpcomDll(dllPath) then
    begin
      //buf := cpd;
      NS_StrCopy(buf, cpd);
      Result := True;
      Exit;
    end;
  end;

  if GetEnvironmentVariableA('USE_LOCAL_GRE', useLocalGre, MAX_PATH)>0 then
  begin
    Result := False;
    Exit;
  end;

  {if SUCCEEDED(GetEnvironmentVariable('HOME', greConfHomePath, MAX_PATH)) and
     (StrLen(path)>0) then
  begin
    StrCat(greConfHomePath, '\gre.config');
    if GetPathFromConfigFile(greConfHomePath, GRELocation) then
    begin
      buf := GRELocation;
      Result := True;
      Exit;
    end;
  end;}

  {if SUCCEEDED(GetEnvironmentVariable('MOZ_GRE_CONF', path, MAX_PATH)) and
     (StrLen(path)>0) then
  begin
    if GetPathFromConfigFile(path, GRELocation) then
    begin
      buf := GRELocation;
      Result := True;
      Exit;
    end;
  end;}

  // レジストリから探す
  if GetLatestGreLocation(buf) then
  begin
    Result := True;
    Exit;
  end;

  Result := False;
{$ELSE}
begin
 {$IFDEF DARWIN}
//  NS_StrCopy(buf, '/Applications/Firefox.app/Contents/MacOS');
  NS_StrCopy(buf, '/Library/Frameworks/XUL.framework/Versions/Current');  
 {$ELSE}  //Linux
  NS_StrCopy(buf, '/usr/lib/xulrunner-1.9.1.4/libxpcom.so');
 {$ENDIF}
  Result := True;
{$ENDIF}
end;

function nsGREDirServiceProvider.GetGreDirectory(out AFile: nsILocalFile): nsresult;
var
  GreDir: TMaxPathChar;
  tempLocal: nsILocalFile;
  leaf: nsCStringContainer;
begin
  Result := NS_ERROR_FAILURE;
  if not GetGREDirectoryPath(GreDir) then Exit;

  ZeroArray(leaf,sizeof(leaf));
  Result := NS_CStringContainerInit(leaf);
  if NS_FAILED(Result) then Exit;
  NS_CStringSetData(@leaf, GreDir);
  Result := NS_NewNativeLocalFile(@leaf, True, tempLocal);

  if NS_SUCCEEDED(Result) then
    Result := tempLocal.QueryInterface(nsILocalFile, AFile);
end;

function nsGREDirServiceProvider.GetFile(const Prop: PAnsiChar; out Persistent: LongBool; out AFile: nsIFile): nsresult;
var
  localFile: nsILocalFile;
const
  NS_GRE_DIR                            = 'GreD';
begin
  persistent := True;

  if NS_StrComp(Prop, NS_GRE_DIR)=0 then
    Result := GetGreDirectory(localFile)
  else
    Result := NS_ERROR_FAILURE;

  if NS_SUCCEEDED(Result) then
    Result := localFile.QueryInterface(nsIFile, AFile);
end;

class function nsGREDirServiceProvider.NewInstance: TObject;
var
  Instance: Pointer;
begin
  Instance := nsMemory.Alloc(InstanceSize);
  Result := InitInstance(Instance);
  nsGREDirServiceProvider(Instance).FRefCount := 1;
end;

procedure nsGREDirServiceProvider.FreeInstance;
begin
  nsMemory.Free(Self);
end;

function GetXPCOMPath(buf: PAnsiChar): Boolean;
var
  grePath: TMaxPathChar;
  greEnv: TMaxPathChar;
begin
{$IFDEF MSWINDOWS}
  Result := False;
  //if not GetGreDirectoryPath(grePath) then
  if NS_FAILED(GRE_GetGREPathWithProperties(nil, 0, nil, 0, grePath, MAX_PATH)) then
  begin
    if GetEnvironmentVariableA('MOZILLA_FIVE_HOME', greEnv, MAX_PATH)=0 then
//FPC port: previous calls don't find Firefox's GRE, so just force it.
      begin
//      NS_StrLCopy(buf, 'C:\Program Files\Mozilla Firefox\xpcom.dll', MAX_PATH);
      NS_StrLCopy(buf, PChar(ExtractFilePath(ParamStr(0)) + 'xulrunner\xpcom.dll'), MAX_PATH);
      if not FileExists(buf) then
        Exit;
      end
    else
      begin
//FPC port
      NS_StrCopy(buf, greEnv);
      NS_StrLCat(buf, '\xpcom.dll', MAX_PATH);
      end
  end else
  begin
    NS_StrCopy(buf, grePath);
  end;
{$ELSE}
  GetGREDirectoryPath(grePath);
  NS_StrCopy(buf, grePath);
 {$IFDEF DARWIN}
  NS_StrLCat(buf, '/libxpcom.dylib', MAX_PATH);
 {$ELSE}  //Linux
  NS_StrLCat(buf, '/libxpcom.so', MAX_PATH);
 {$ENDIF}
{$ENDIF}

  Result := True;
end;

var
  sStartupCount: Integer = 0;

function GRE_Startup: nsresult;
var
  xpcomLocation: TMaxPathChar;
  provider: nsGREDirServiceProvider;
  servMgr: nsIServiceManager;
begin
  Result := NS_OK;

  if sStartupCount > 0 then
  begin
    Inc(sStartupCount);
    Exit;
  end;

  GetXPCOMPath(xpcomLocation);

  Result := XPCOMGlueStartup(xpcomLocation);

  if NS_FAILED(Result) then Exit;

  provider := nsGREDirServiceProvider.Create;
  if not Assigned(provider) then
  begin
    Result := NS_ERROR_OUT_OF_MEMORY;
    XPCOMGlueShutdown;
    Exit;
  end;

  provider._AddRef;
  Result := NS_InitXPCOM2(servMgr, nil, provider as nsXPCOM.nsIDirectoryServiceProvider);
  provider._Release;

  if NS_FAILED(Result) then
  begin
    XPCOMGlueShutdown;
    Exit;
  end;
  Inc(sStartupCount);
end;

function GRE_Shutdown: nsresult;
begin
  Dec(sStartupCount);

  if sStartupCount=0 then
  begin
    NS_ShutdownXPCOM(nil);
    //XPCOMGlueShutdown;
  end else
  if sStartupCount<0 then sStartupCount := 0;

  Result := NS_OK;
end;

function NS_CompareVersion(A, B: PAnsiChar): PRInt32;
var
  vA, vB: TGREVersion;
begin
  va := GetGREVersion(A);
  vB := GetGREVersion(b);

  Result := GREVersionCompare(vA, vB);
end;

{ PChar routines }

function NS_StrLen(const Str: PAnsiChar): Cardinal;
var
  P: PAnsiChar;
begin
  P := Str;
  Result := 0;
  while P^ <> #0 do
  begin
    Inc(P);
    Inc(Result);
  end;
end;

function NS_StrCopy(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar;
var
  D, S: PAnsiChar;
begin
  D := Dest;
  S := Source;
  repeat
    D^ := S^;
    Inc(D);
    Inc(S);
  until D[-1] = #0;
  Result := Dest;
end;

function NS_StrLCopy(Dest: PAnsiChar; const Source: PAnsiChar; maxLen: Cardinal): PAnsiChar;
var
  D, S, last: PAnsiChar;
begin
  D := Dest;
  S := Source;
  last := Dest + maxLen;
  while (S^<>#0) and (D < last) do
  begin
    D^ := S^;
    Inc(D);
    Inc(S);
  end;
  D^ := #0;
  Result := Dest;
end;

function NS_StrCat(Dest: PAnsiChar; const Source: PAnsiChar): PAnsiChar;
var
  D: PAnsiChar;
begin
  D := Dest;
  while D^ <> #0 do
    Inc(D);
  NS_StrCopy(D, Source);
  Result := Dest;
end;

function NS_StrLCat(Dest: PAnsiChar; const Source: PAnsiChar; maxLen: Cardinal): PAnsiChar;
var
  D, S: PAnsiChar;
  last: PAnsiChar;
begin
  D := Dest + StrLen(Dest);
  S := Source;
  last := Dest + maxLen - 1;
  while (S^ <> #0) and (D < last) do
  begin
    D ^ := S^;
    Inc(D);
    Inc(S);
  end;
  D^ := #0;
  Result := Dest;
end;

function NS_StrComp(const Str1, Str2: PAnsiChar): Integer;
var
  P1, P2: PAnsiChar;
begin
  P1 := Str1;
  P2 := Str2;
  while (P1^<>#0) and (P1^=P2^) do
  begin
    Inc(P1);
    Inc(P2);
  end;
  Result := Ord(P1^) - Ord(P2^);
end;

function NS_StrRScan(const Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
var
  P: PAnsiChar;
begin
  P := Str;
  while P^<>#0 do
    Inc(P);
  while (P>=Str) and (P^<>Chr) do
    Dec(P);
  if (P>=Str) then
    Result := P
  else
    Result := nil;
end;

function NS_StrLen(const Str: PWideChar): Cardinal;
var
  P: PWideChar;
begin
  P := Str;
  Result := 0;
  while P^ <> #0 do
  begin
    Inc(P);
    Inc(Result);
  end;
end;

function NS_StrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar;
var
  D, S: PWideChar;
begin
  D := Dest;
  S := Source;
  repeat
    D^ := S^;
    Inc(D);
    Inc(S);
  until D[-1] = #0;
  Result := Dest;
end;

function NS_StrLCopy(Dest: PWideChar; const Source: PWideChar; maxLen: Cardinal): PWideChar;
var
  D, S: PWideChar;
begin
  D := Dest;
  S := Source;
  while (S^<>#0) and (Dest+maxLen<D) do
  begin
    D^ := S^;
    Inc(D);
    Inc(S);
  end;
  D^ := #0;
  Result := Dest;
end;

function NS_StrCat(Dest: PWideChar; const Source: PWideChar): PWideChar;
var
  D: PWideChar;
begin
  D := Dest;
  while D^ <> #0 do
    Inc(D);
  NS_StrCopy(D, Source);
  Result := Dest;
end;

function NS_StrLCat(Dest: PWideChar; const Source: PWideChar; maxLen: Cardinal): PWideChar;
var
  D, S: PWideChar;
  last: PWideChar;
begin
//  D := Dest + StrLen(Dest);  //Doesn't compile with Delphi 7 or FPC.
  D := Dest + Length(WideString(Dest));  //This line inserted.
  S := Source;
  last := Dest + maxLen - 1;
  while (S^ <> #0) and (D < last) do
  begin
    D ^ := S^;
    Inc(D);
    Inc(S);
  end;
  D^ := #0;
  Result := Dest;
end;

function NS_StrComp(const Str1, Str2: PWideChar): Integer;
var
  P1, P2: PWideChar;
begin
  P1 := Str1;
  P2 := Str2;
  while (P1^<>#0) and (P1^=P2^) do
  begin
    Inc(P1);
    Inc(P2);
  end;
  Result := Ord(P1^) - Ord(P2^);
end;

function NS_StrRScan(const Str: PWideChar; Chr: WideChar): PWideChar;
var
  P: PWideChar;
begin
  P := Str;
  while P^<>#0 do
    Inc(P);
  while (P>=Str) and (P^<>Chr) do
    Dec(P);
  if (P>=Str) then
    Result := P
  else
    Result := nil;
end;

function safe_strncat(Dest: PAnsiChar; Append: PAnsiChar; count: PRUint32): PRBool;
var
  last: PAnsiChar;
begin
  last := (dest+count-1);
  while dest^ <> #0 do
    Inc(dest);
  while (append^ <> #0) and (Last - Dest > 0) do
  begin
    Dest^ := Append^;
    Inc(dest);
    Inc(Append);
  end;
  Dest^ := #0;
  Result := (Append^ = #0);
end;

function fullpath(absPath, relPath: PAnsiChar; maxLength: PRUint32): PAnsiChar;
begin
  //Path here must arrive already absolute :-?
  strlcopy(abspath,relpath,maxLength);
//  GetFullPathNameA(relPath, maxLength, absPath, filePart);
  Result := absPath;
end;

function NS_CurrentProcessDirectory(buf: PAnsiChar; bufLen: Cardinal): Boolean;
var
  lastSlash: PAnsiChar;
begin
  Result := False;
  move(ParamStr(0)[1],buf^,min(bufLen,Length(ParamStr(0))));
  lastSlash := NS_StrRScan(buf, '\');
  if Assigned(lastSlash) then
  begin
    lastSlash^ := #0;
    Result := True;
  end;
end;

procedure ZeroArray(out AArray; const ASize: SizeInt);
begin
{$PUSH}{$HINTS OFF}
  FillByte(AArray,ASize,0);
{$POP}
end;


end.
