|
|
#ifndef _CDL_H_
#define _CDL_H_
#define MAX_DEBUG_STRING_LENGTH 2048
#define MAX_DEBUG_FORMAT_STRING_LENGTH 1024
#define MAX_VERSIONLENGTH 27 // sizeof(2DWORDS)/(log 10 base 2) + 3 (seperators)
// == 64/3 + 3 == 25
// CDL.h
// Code Downloader header file
//
// Read "class descriptions" first for understanding how the
// code downloader works.
#define STRING(x) (((x) != NULL) ? (x) : (L"(null)"))
#ifndef ARRAY_ELEMENTS
#define ARRAY_ELEMENTS(array) \
(sizeof(array)/sizeof(array[0])) #endif /* ARRAY_ELEMENTS */
#include <safeocx.h>
#include "debmacro.h"
#include <msxml.h>
#include "wvtp.h"
//#include "..\inc\clist.hxx"
#ifndef unix
#include "..\utils\coll.hxx"
#else
#include "../utils/coll.hxx"
#endif /* !unix */
#include "packet.hxx"
#include "shlwapi.h"
#include "strids.h"
#include <pkgmgr.h>
#ifdef WX86
#ifdef __cplusplus // make classes invisible to 'C'
// Support for multiple architectures during code download. This must
// be declared before softdist.hxx can be included.
class CMultiArch { public: CMultiArch() { m_RequiredArch = PROCESSOR_ARCHITECTURE_UNKNOWN; }; DWORD GetRequiredArch() { return m_RequiredArch;} HRESULT RequirePrimaryArch(); HRESULT RequireAlternateArch(); VOID SelectArchitecturePreferences( char *szNativeArch, char *szIntelArch, char **pszPreferredArch, char **pszAlternateArch);
private: DWORD m_RequiredArch; }; #endif
#endif
#include "softdist.hxx"
#include <capi.h>
#define MAX_REGSTR_LEN 1024
#define DU_TAG_SOFTDIST L"SOFTPKG"
#define DU_TAG_NATIVECODE L"msicd::NativeCode"
#define DU_TAG_JAVA L"msicd::Java"
#define DU_TAG_EXPIRE L"msicd::Expire"
#define DU_TAG_UNINSTALL_OLD L"msicd::UninstallOld"
#define INF_TAG_UNINSTALL_OLD "UninstallOld"
#define DU_TAG_CODE L"Code"
#define DU_TAG_CODEBASE L"CodeBase"
#define DU_TAG_PACKAGE L"Package"
#define DU_TAG_TITLE L"TITLE"
#define DU_TAG_ABSTRACT L"ABSTRACT"
#define DU_TAG_LANG L"LANGUAGE"
#define DU_TAG_DEPENDENCY L"Dependency"
#define DU_TAG_PROCESSOR L"Processor"
#define DU_TAG_PLATFORM L"Platform"
#define DU_TAG_CONFIG L"IMPLEMENTATION"
#define DU_TAG_USAGE L"Usage"
#define DU_TAG_OS L"OS"
#define DU_TAG_OSVERSION L"OSVersion"
#define DU_TAG_NAMESPACE L"NameSpace"
#define DU_TAG_DELETEONINSTALL L"DeleteOnInstall"
#define DU_ATTRIB_NAME L"NAME"
#define DU_ATTRIB_FILENAME L"FILENAME"
#define DU_ATTRIB_VALUE L"VALUE"
#define DU_ATTRIB_VERSION L"VERSION"
#define DU_ATTRIB_STYLE L"STYLE"
#define DU_ATTRIB_SIZE L"SIZE"
#define DU_ATTRIB_PRECACHE L"PRECACHE"
#define DU_ATTRIB_AUTOINSTALL L"AUTOINSTALL"
#define DU_ATTRIB_EMAIL L"EMAIL"
#define DU_ATTRIB_HREF L"HREF"
#define DU_ATTRIB_ACTION L"ACTION"
#define DU_ATTRIB_CLSID L"CLASSID"
#define DU_ATTRIB_DL_GROUP L"GROUP"
#define DU_ATTRIB_RANDOM L"RANDOM"
#define DU_STYLE_MSICD "MSICD"
#define DU_STYLE_ACTIVE_SETUP "ActiveSetup"
#define DU_STYLE_MSINSTALL "MSInstall.SoftDist"
#define DU_STYLE_LOGO3 "MSAppLogo5"
#define DU_TAG_SYSTEM L"System"
// Used by JAVA
#define DU_TAG_NEEDSTRUSTEDSOURCE L"NeedsTrustedSource"
#define CHANNEL_ATTRIB_BASE L"BASE"
#define MAX_EXPIRE_DAYS 3650
#ifdef __cplusplus
extern "C" { #endif
#include "fdi.h"
#ifndef DEB_CODEDL
#define DEB_CODEDL 1
#endif
// JIT Window data
#define JIT_DIALOG_CLASS_NAME "Internet Explorer_TridentDlgFrame"
#define JIT_DIALOG_CAPTION "Internet Explorer Install on Demand"
// return value from the JIT setup page.
#define JITPAGE_RETVAL_SUCCESS 0x0 // successfully installed
#define JITPAGE_RETVAL_CANCELLED 0x1 // was cancelled by user
#define JITPAGE_RETVAL_DONTASK_THISWINDOW 0x2 // don;t ask again in this
// window
#define JITPAGE_RETVAL_DONTASK_EVER 0x3 // don't ask ever. user
// goes to addon page to
// install
#define JITPAGE_RETVAL_NEED_REBOOT ERROR_SUCCESS_REBOOT_REQUIRED
// FaultInIEFeature flags
// urlmon.idl flag definition
// internal flags are here
#define FIEF_FLAG_CHECK_CIFVERSION 0x100 // checks if requested version
// can be installed by JIT
#define REGSTR_PATH_INFODEL_REST "Software\\Policies\\Microsoft\\Internet Explorer\\Infodelivery\\Restrictions"
#define REGVAL_JIT_REST "NoJITSetup"
#define REGKEY_WEBJITURLS "Software\\Microsoft\\Active Setup\\WebJITURLS"
#define REGVAL_WEBJIT_REST "NoWebJITSetup"
#define REGVAL_UI_REST "NoWinVerifyTrustUI"
// registry paths for ModuleUsage
#define REGSTR_PATH_SHAREDDLLS "Software\\Microsoft\\Windows\\CurrentVersion\\SharedDlls"
#define REGSTR_PATH_MODULE_USAGE "Software\\Microsoft\\Windows\\CurrentVersion\\ModuleUsage"
#define REGSTR_PATH_CODE_STORE "Software\\Microsoft\\Code Store Database"
#define REGSTR_PATH_DIST_UNITS "Software\\Microsoft\\Code Store Database\\Distribution Units"
#define REGSTR_PATH_JAVA_PKGS "Software\\Microsoft\\Code Store Database\\Java Packages"
#define REGSTR_PATH_IE_SETTINGS "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"
#define REGSTR_PATH_IE_MAIN "Software\\Microsoft\\Internet Explorer\\Main"
#define REGSTR_PATH_LOGO3_SETTINGS "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
#define REGVAL_LOGO3_MAJORVERSION "VersionMajor"
#define REGVAL_LOGO3_MINORVERSION "VersionMinor"
#define REGSTR_LOGO3_ADVERTISED_VERSION "AdvertisedVersion"
#define REGKEY_LOGO3_AVAILABLE_VERSION "AvailableVersion"
#define REGSTR_PATH_NT5_LOCKDOWN_TEST "Software\\Microsoft\\Code Store Database\\NT5LockDownTest"
#define REGVAL_USE_COINSTALL "UseCoInstall"
// If you modify this then make appropriate entries in urlmon\dll\selfreg.inx
// to clean this out on urlmon dlluninstall
// this key will be renamed before ship of each major release
// so we won't remember the rejected features in PP1 and not prompt for final
// release
#define REGKEY_DECLINED_COMPONENTS "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Declined Components IE5"
#define REGKEY_DECLINED_IOD "Software\\Microsoft\\Active Setup\\Declined Install On Demand IEv5"
#define REGKEY_ACTIVESETUP_COMPONENTS "Software\\Microsoft\\Active Setup\\Installed Components"
#define REGKEY_ACTIVESETUP "Software\\Microsoft\\Active Setup"
#define REGKEY_ACTIVESETUP_CLSIDFEATURE "Software\\Microsoft\\Active Setup\\ClsidFeature"
#define REGKEY_ACTIVESETUP_MIMEFEATURE "Software\\Microsoft\\Active Setup\\MimeFeature"
#define REGKEY_ACTIVESETUP_FEATURECOMPID "Software\\Microsoft\\Active Setup\\FeatureComponentID"
#define REGVAL_VERSION_AVAILABLE "Version available"
#define REGVAL_VERSION_ADVERTISED "Version advertised"
#define REGVAL_ABSTRACT_AVAILABLE "Abstract"
#define REGVAL_TITLE_AVAILABLE "Title available"
#define REGVAL_HREF_AVAILABLE "HREF available"
#define REGVAL_FIRST_HOME_PAGE "First Home Page"
#define REGKEY_MSICD_ADVERTISED_VERSION "AdvertisedVersion"
#define REGVAL_ADSTATE "AdState"
#define DISTUNIT_NAME_IE4 "{89820200-ECBD-11cf-8B85-00AA005B4383}"
// Code Download Setup Flags
// DWORD g_dwCodeDownloadSetupFlags = 0;
typedef enum { CDSF_INIT, CDSF_USE_SETUPAPI } CodeDownloadSetupFlags;
// buffer size for downloads in CBSC::m_cbuffer
#define BUFFERMAX 2048
// File Name List
//
// used as pFilesToExtract to track files in the CAB we need extracted
//
// or a pFileList in PSESSION
//
// We keep track of all files that are in a cabinet
// keeping their names in a list and when the download
// is complete we use this list to delete temp files
struct sFNAME { LPSTR pszFilename; struct sFNAME *pNextName; DWORD status; /* out */ };
typedef struct sFNAME FNAME; typedef FNAME *PFNAME;
// SFNAME.status: success is 0 or non-zero error code in extraction
#define SFNAME_INIT 1
#define SFNAME_EXTRACTED 0
// FILE extentions we know about
typedef enum { FILEXTN_NONE, FILEXTN_UNKNOWN, FILEXTN_CAB, FILEXTN_DLL, FILEXTN_OCX, FILEXTN_INF, FILEXTN_EXE, FILEXTN_OSD, FILEXTN_CAT } FILEXTN;
//
// Master State Information for File Extraction: used by extract.c
//
typedef struct { UINT cbCabSize; ERF erf; PFNAME pFileList; // List of Files in CAB
UINT cFiles; DWORD flags; // flags: see below for list
char achLocation[MAX_PATH]; // Dest Dir
char achFile[MAX_PATH]; // Current File
char achCabPath[MAX_PATH]; // Current Path to cabs
PFNAME pFilesToExtract; // files to extract;null=enumerate only
} SESSION, *PSESSION;
typedef enum { SESSION_FLAG_NONE = 0x0, SESSION_FLAG_ENUMERATE = 0x1, SESSION_FLAG_EXTRACT_ALL = 0x2, SESSION_FLAG_EXTRACTED_ALL = 0x4 } SESSION_FLAGS;
typedef struct CodeDownloadDataTag { LPCWSTR szDistUnit; // Distribution unit to look for
LPCWSTR szClassString; // clsid (or class string) of object desired
LPCWSTR szURL; // codebase to download
LPCWSTR szMimeType; // mime type (com translate -> clsid)
LPCWSTR szExtension; // extension (com translate -> clsid)
LPCWSTR szDll; // dll to load object from after download (for zero impact)
DWORD dwFileVersionMS; // file version
DWORD dwFileVersionLS; DWORD dwFlags; // flags
} CodeDownloadData;
#define chPATH_SEP1 '\\'
#define chPATH_SEP2 '/'
#define chDRIVE_SEP ':'
// size of [Add.Code] section in INF in bytes
#define MAX_INF_SECTIONS_SIZE 1024
// from extract.c
HRESULT Extract(PSESSION psess, LPCSTR lpCabName); HRESULT ExtractFromCabinet(PSESSION ps, LPCSTR lpCabFileName); VOID DeleteExtractedFiles(PSESSION psess); BOOL catDirAndFile( char *pszResult, int cbResult, char *pszDir, char *pszFile);
#ifdef __cplusplus
} #endif
#define CHECK_ERROR_EXIT(cond, iResID) if (!(cond)) { \
if (iResID) \ CodeDownloadDebugOut(DEB_CODEDL, TRUE, iResID); \ goto Exit;}
// Download states that a CDownload passes thru from obj creation to done.
typedef enum { DLSTATE_INIT, // obj constructed
DLSTATE_BINDING, // download in progress
DLSTATE_DOWNLOADED, // at begining of OnStopBinding
DLSTATE_EXTRACTING, // begin CAB extraction (where applicable)
DLSTATE_INF_PROCESSING, // begin ProcessInf (where applicable)
DLSTATE_READY_TO_SETUP, // end of OnStopBinding
DLSTATE_SETUP, // Start DoSetup
DLSTATE_DONE, // all done, ready to free obj,
// delete temp files
DLSTATE_ABORT // aborted this download
} DLSTATE;
// INSTALL_STATE used to give BINDSTATUS_INSTALLING_COMPONENTS OnProgress
// during setup phase
// given as INSTALL_COPY of INSTALL_PHASES, szStatusText pointing to filename
typedef enum { INSTALL_INIT = 0, INSTALL_VERIFY = 1, INSTALL_COPY = 2, INSTALL_REGISTER =3, INSTALL_PHASES = 4 } INSTALL_STATE;
#define INSTALL_DONE INSTALL_PHASES
// directions to CSetup on dest dir for file if no prev version exists
typedef enum {
LDID_OCXCACHE=0, // ocxcache dir, now = windows\ocxcache
LDID_WIN=10, // INF convetion to mean windows dir
LDID_SYS=11 // INF convetion to mean sysdir
} DESTINATION_DIR ;
// Software distribution styles
typedef enum { STYLE_UNKNOWN = -1, // Unknown otherwise.
STYLE_MSICD = 1, STYLE_ACTIVE_SETUP, STYLE_LOGO3, STYLE_MSINSTALL, // Darwin
STYLE_OTHER // Provides own ISoftDistExt interface for access
};
#ifdef __cplusplus // make classes invisible to 'C'
#include "langcode.h"
// <Config> tag processor. Shared by Code Download and CSoftDist.
HRESULT ProcessImplementation(IXMLElement *pConfig, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList, LCID lcidOverride, #ifdef WX86
CMultiArch *MultiArch, #endif
LPWSTR szBaseURL = NULL); HRESULT ProcessCodeBaseList(IXMLElement *pCodeBase, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList, LPWSTR szBaseURL = NULL);
// %%Classes: ----------------------------------------------------------------
/*
* class descriptions * * CCodeDownload (main class tracking as a whole) * It has the client's BSC and creates a CClBinding for client. * * CClBinding (For client's IBinding for code download) * * CDownload (tracks individual downloads) implements a * * CBindStatusCallback (BSC) * * Csetup obj: zero or more associated with every CDownload obj * Some CDownload's may have no CSetup (eg. INF file) * * * * * We do our code download in 2 stages. * 1) download stage * 2) setup and registeration stage * * CCodeDownload is the main class for codedownload. * AsyncGetClassBits() the entry into the Code downloader creates this obj * for the given CODE, CLSID, FileVersion, BSC (from BindCtx) * we do not check to see if a code download is already in progress * in the system at a given moment. Nor we do we keep track of individual * downloads and possible clashes between various silmultaneous code * downloads system wide. We leave it to URL moniker (above us) to ensure * that duplicate calls are not made into AsynGetClassBits. The second * problem of different code downloads trying to bring down a common * dependent DLL is POSTPONED to version 2 implementation. * * The CodeDownload obj once created is asked to perform its function * thru CCodeDownload::DoCodeDownload(). * This triggers creation of the first CDownload object for the CODE url * if a local check for CLSID,FileVersion returns update_needed. * (note : it is interesting to note here that if a control needs to just * update a dependent DLL file it still needs to update the FileVersion * of the primary control file (with CLSID implementation) for triggering * any download at all! * * Once DoCodeDownload determines that an update is in order it creates * a CClBinding for its client to call client BSC::OnstartBinding with. * * It then adds this CDownload obj to its list of downloads. * * If the m_url is a CAB or INF we need to download it before we know * what we need to do next. Otherwise we create a CSetup obj for the * download and add it to CDownload's list of pending Setup processing for * stage 2 (setup and registeration). CSetup details later. * * CDownload is the basic download obj. It's action entry point is DoDownload * Here it creates a URL moniker for the given m_url and a bind ctx to go * with it and then calls pmk->BindToStorage to get the bits. Note how we * use URL mon's services to get the bits even as URLmon is our client for * the Code Download. We are its client for individual downloads. CDownload * has a BSC implementation to track progress and completion. This BSC is * where the magic of taking us from one state to next occurs. * * BSC::OnProgress * Here we get the master CodeDownload obj to collate progress and report * cumulative code download progress to client BSC::OnProgress. * * BSC::OnDataAvailable * At the last notification we get the filename URLmon has downloaded the * m_url data to and rename it to a file in the temp dir. * * BSC:: OnStopBinding * we get here when we have fully downloaded 'this'. this is the place * to call into WinVerifyTrust api if appropriate * This triggers a change state in our state machine. Depending on the * obj we have downloaded (a CAB or INF or DLL/OCX/EXE) we: * * OCX: * Csetup for this download is usually previously created * mark this download as done and * call into main CodeDownload::CompleteOne (state analyser) * * CAB: * if we don't have an INF already we look for one in the CAB * if INF in CAB * process INF (may trigger further extractions/downloads/Csetup) * else * look for primary OCX in CAB and create CSetup or it. * * INF: * Process INF * * CCodeDownload::CompleteOne is called whenever a CDownload obj completes * its download and initiates further downloads if necessary (eg. ProcessInf) * It does nothing until all pending downloads are complete. Until then it * just returns and we unwind back to BSC::OnStopBinding * * When all downloads completed, we then start processingall the Csetups * We do this code download in two stages to * keep capability to back out of entire code download for as late as we can * until the setup stage calling CClBinding::Abort with IBinding returned by * code downloader in client's BSC::OnStartBinding will cleanly abort and * restore initial state. * We don't honor Abort once in setup stage. * * To keep this stage as clean and failsafe as we can we check for * disk space in the OCX cache as well as check for IN USE OCXes that we * plan on updating. We abort on either of these two conditions. * * CCodeDownload::CompleteOne than proceeds to walk thru all its download objs * calling DoSetup which in turn causes CSetup::DoSetup() to get invoked * for every CSetup. * * In the guts of Csetup we move the temp OCX file to the dest dir ( usually * OCXCACHE dir unless upgrading over previous version), and we call * register OCX (if version info suggests so) * * When done with the setup stage CompleteOne calls client's BSC::OnStopBinding * and then frees all memory and clens up temp files. * */
class CLocalComponentInfo { public:
CLocalComponentInfo(); ~CLocalComponentInfo(); HRESULT MakeDestDir();
BOOL IsPresent() { return (dwLocFVMS | dwLocFVLS); } BOOL IsLastModifiedTimeAvailable() { return ( ftLastModified.dwHighDateTime | ftLastModified.dwLowDateTime); } FILETIME * GetLastModifiedTime() { return IsLastModifiedTimeAvailable()?&ftLastModified:NULL; }
LPSTR GetLocalVersionEtag() { return pbEtag;}
LCID GetLocalVersionLCID() { return lcid; }
// data members
char szExistingFileName[MAX_PATH]; LPSTR pBaseExistingFileName; LPSTR lpDestDir; DWORD dwLocFVMS; DWORD dwLocFVLS; FILETIME ftLastModified; LPSTR pbEtag; LCID lcid; BOOL bForceLangGetLatest; DWORD dwAvailMS; DWORD dwAvailLS; };
// CModuleUsage: created for every module added to ModuleUsage
// is walked thru and run after all setups are complete in COmpleteAll
// can also be used to optionally rollback a setup
class CModuleUsage { public:
// constructor
CModuleUsage(LPCSTR lpFileName, DWORD dwFlags, HRESULT *phr); ~CModuleUsage();
HRESULT Update(LPCSTR szClientName); LPCSTR GetFileName() {return m_szFileName;}
// data members
LPSTR m_szFileName; DWORD m_dwFlags; };
// CSetup: created for every setup item
// each CDownload has zero or more of these linked into a list
typedef enum {
// the default behaviour for
// registering a server is to do
// so only when the version rsrc
// has the string "OleSelfregister"
// the user can override this
// behaviour with setting in .INF
// registerserver=yes/no
CST_FLAG_REGISTERSERVER_OVERRIDE=1, // when set user has overriden
CST_FLAG_REGISTERSERVER=2 // when set along with above
// means user wants us to register
// server
} CST_FLAGS;
class CDownload;
typedef enum { CJS_FLAG_INIT=0, CJS_FLAG_NOSETUP=1, // don't setup just mark that this
// java package is used by this dist
// unit.
CJS_FLAG_SYSTEM=2, // system class
CJS_FLAG_NEEDSTRUSTEDSOURCE=4, // need trusted source
};
class CJavaSetup { public:
CJavaSetup( CDownload *pdl, LPCWSTR szPackageName, LPCWSTR szNameSpace, IXMLElement *pPackage, DWORD dwVersionMS, DWORD dwVersionLS, DWORD flags, HRESULT *phr);
~CJavaSetup();
HRESULT DoSetup();
INSTALL_STATE GetState() const { return m_state;} VOID SetState(INSTALL_STATE state) { m_state = state;}
LPCWSTR GetPackageName() { return m_szPackageName; } LPCWSTR GetNameSpace() { return m_szNameSpace; } void GetPackageVersion(DWORD &dwVersionMS, DWORD &dwVersionLS) { dwVersionMS = m_dwVersionMS; dwVersionLS = m_dwVersionLS; } DWORD GetPackageFlags() { return m_flags; } IXMLElement *GetPackageXMLElement() { return m_pPackage; }
private:
INSTALL_STATE m_state; // state of install operation
CDownload* m_pdl; LPWSTR m_szPackageName; LPWSTR m_szNameSpace; IXMLElement * m_pPackage; DWORD m_dwVersionMS; DWORD m_dwVersionLS; DWORD m_flags; };
class CSetup {
public:
HRESULT DoSetup(CCodeDownload *pcdl, CDownload *pdl);
LPCSTR GetSrcFileName() const {return m_pSrcFileName;}
HRESULT SetSrcFileName(LPCSTR pSrcFileName);
FILEXTN GetExtn() const {return m_extn;}
CSetup *GetNext() const { return m_pSetupnext;} VOID SetNext(CSetup *pSetupnext) { m_pSetupnext = pSetupnext;}
INSTALL_STATE GetState() const { return m_state;} VOID SetState(INSTALL_STATE state) { m_state = state;}
LPCSTR GetBaseFileName() const { return m_pBaseFileName; }
// constructor
CSetup(LPCSTR pSrcFileName, LPCSTR pBaseFileName, FILEXTN extn, LPCSTR pDestDir, HRESULT *phr, DESTINATION_DIR dest = LDID_OCXCACHE); ~CSetup();
HRESULT GetDestDir(CCodeDownload *pcdl, LPSTR szDestDir, int iLen);
HRESULT CheckForNameCollision(CCodeDownload *pcdl, LPCSTR szCacheDir);
HRESULT InstallFile( CCodeDownload *pcdl, LPSTR szDestDir, int iLen, LPWSTR szStatusText, LPUINT pcbStatusText);
VOID SetCopyFlags(DWORD dwcf) { m_advcopyflags = dwcf; }
VOID SetUserOverrideRegisterServer(BOOL fRegister) { m_flags |= CST_FLAG_REGISTERSERVER_OVERRIDE; if (fRegister) { m_flags |= CST_FLAG_REGISTERSERVER; } }
BOOL UserOverrideRegisterServer() { return (m_flags & CST_FLAG_REGISTERSERVER_OVERRIDE); }
BOOL WantsRegisterServer() { return (m_flags & CST_FLAG_REGISTERSERVER); }
void SetExactVersion(BOOL bFlag) {m_bExactVersion = bFlag;}
private:
CSetup* m_pSetupnext;
LPSTR m_pSrcFileName; // fully qualified src file name
LPSTR m_pBaseFileName; // base filename
FILEXTN m_extn;
LPCSTR m_pExistDir; // dest dir for setting up obj
// if null default to ocxcache dir
INSTALL_STATE m_state; // state of install operation
DESTINATION_DIR m_dest;
DWORD m_flags; // overrides for register server
DWORD m_advcopyflags; // flags for AdvInstallFile
BOOL m_bExactVersion; };
// CClBinding to pass to client of CodeDownload in client's BSC::OnStartBinding
class CClBinding : public IBinding {
public:
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid,void ** ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
// IBinding methods
STDMETHOD(Abort)( void); STDMETHOD(Suspend)( void); STDMETHOD(Resume)( void); STDMETHOD(SetPriority)(LONG nPriority); STDMETHOD(GetPriority)(LONG *pnPriority); STDMETHOD(GetBindResult)(CLSID *pclsidProtocol, DWORD *pdwResult, LPWSTR *pszResult,DWORD *pdwReserved);
CClBinding::CClBinding( CCodeDownload *pcdl, IBindStatusCallback *pAssClientBSC, IBindCtx *pAssClientBC, REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, IInternetHostSecurityManager* m_pHostSecurityManager);
~CClBinding();
HRESULT InstantiateObjectAndReport(CCodeDownload *pcdl);
REFCLSID GetClsid() const { return m_clsid;}
HRESULT ReleaseClient();
DWORD GetState() const { return m_dwState;} VOID SetState(DWORD dwState) { m_dwState = dwState;}
IBindStatusCallback* GetAssBSC() {return m_pAssClientBSC;}
IBindCtx* GetAssBC() {return m_pAssClientBC;}
ICodeInstall* GetICodeInstall(); // side-effect: sets m_pCodeInstall!
IWindowForBindingUI* GetIWindowForBindingUI(); // side-effect: sets m_pWindowForBindingUI!
IBindHost* GetIBindHost(); // side-effect: sets m_pBindHost!
IInternetHostSecurityManager* GetHostSecurityManager();
HWND GetHWND(REFGUID rguidReason = IID_ICodeInstall);
HRESULT SetClassString(LPCWSTR pszClassString); const LPWSTR GetClassString();
private:
CLSID m_clsid; // foll: for CoGetClassObject
DWORD m_dwClsContext; // CLSCTX flags
LPVOID m_pvReserved; // Must be NULL
REFIID m_riid; // Usually IID_IClassFactory
DWORD m_cRef; LONG m_nPriority; // priority of this binding
DWORD m_dwState; // state of operation
CCodeDownload* m_pcdl; IBindStatusCallback* m_pAssClientBSC; // associated Client BSC
IBindCtx* m_pAssClientBC; // associated client bind ctx
IBindHost* m_pBindHost; // IBindHost
IWindowForBindingUI* m_pWindowForBindingUI; // IWindowForBindingUI
// passed in by client
// to pass in hwnd for
// WinVerifyTrust as well
IInternetHostSecurityManager* m_pHostSecurityManager;
ICodeInstall* m_pCodeInstall; // ICodeInstall
// passed in by client
// to pass in hwnd for
// WinVerifyTrust as well
// as handle module update
// contingencies like
// out of disk space and
// permission to update
// existing file with newer ver
HWND m_hWnd; // client hwnd obtained thru
// ICodeInstall
// ::NeedVerificationUI
// safe to cache this?
LPWSTR m_wszClassString; };
// CodeDownload states
typedef enum { CDL_NoOperation = 0, // operation did not start yet
CDL_Downloading, // downloading in progress
CDL_Suspend, // operation suspended
CDL_Aborted, // operation aborted
CDL_ReadyToSetup, // ready to setup
CDL_Setup, // setup in progress
CDL_SetupDone, // setup done
CDL_Completed // done, and complete signalled CompleteAll
} CDL_STATE;
// values for CCodeDownload::m_flags
// these will be defined in objbase.h. For now make sure they are defined so we don't break the build
#ifndef CD_FLAGS_DEFINED
#define CD_FLAGS_DEFINED
typedef enum { CD_FLAGS_INIT = 0x0, CD_FLAGS_FORCE_DOWNLOAD = 0x1, CD_FLAGS_PEEK_STATE = 0x2, CD_FLAGS_NEED_CLASSFACTORY = 0x4, CD_FLAGS_PARANOID_VERSION_CHECK = 0x8, CD_FLAGS_SKIP_DECLINED_LIST_CHECK = 0x20, CD_FLAGS_USE_CODEBASE_ONLY = 0x80, // Set by OLE32 Class Store
CD_FLAGS_HINT_JAVA = 0x100, // to turn off advance
// disabling of code download
// if ActiveX Signed+Unsigned
// is off unless this flag is
// passed any distunit that looks
// like a clsid will not code
// download if ActiveX is off
CD_FLAGS_HINT_ACTIVEX = 0x200, CD_FLAGS_FORCE_INTERNET_DOWNLOAD = 0x400, // For OLE32 CoInstall
// below are internal flags
CD_FLAGS_WAITING_FOR_EXE = 0x40, CD_FLAGS_SILENTOPERATION = 0x800, CD_FLAGS_NEED_REBOOT = 0x1000, CD_FLAGS_BITS_IN_CACHE = 0x2000, CD_FLAGS_NEW_CONTEXT_MONIKER = 0x4000, CD_FLAGS_FAKE_SUCCESS = 0x8000, CD_FLAGS_DELETE_EXE = 0x10000, CD_FLAGS_UNSAFE_ABORT = 0x20000, CD_FLAGS_USER_CANCELLED = 0x40000, CD_FLAGS_HAVE_INF = 0x80000, CD_FLAGS_ONSTACK = 0x100000, CD_FLAGS_USED_CODE_URL = 0x200000, CD_FLAGS_EXACT_VERSION = 0x400000, CD_FLAGS_TRUST_SOME_FAILED = 0x800000
} CD_FLAGS;
#endif // CD_FLAGS_DEFINED
#define CD_FLAGS_EXTERNAL_MASK (CD_FLAGS_FORCE_DOWNLOAD| \
CD_FLAGS_PEEK_STATE| \ CD_FLAGS_NEED_CLASSFACTORY| \ CD_FLAGS_PARANOID_VERSION_CHECK| \ CD_FLAGS_SKIP_DECLINED_LIST_CHECK| \ CD_FLAGS_USE_CODEBASE_ONLY| \ CD_FLAGS_HINT_JAVA| \ CD_FLAGS_HINT_ACTIVEX| \ CD_FLAGS_FORCE_INTERNET_DOWNLOAD)
class CDownload; class DebugLogElement; class CDLDebugLog;
// main class
class CCodeDownload {
public:
// constructor
CCodeDownload( LPCWSTR szDistUnit, LPCWSTR szURL, LPCWSTR szType, LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS, HRESULT *phr);
~CCodeDownload();
HRESULT DoCodeDownload( CLocalComponentInfo *plci, DWORD flags);
HRESULT CCodeDownload::CreateClientBinding( CClBinding **ppClientBinding, IBindCtx* pClientBC, IBindStatusCallback* pClientbsc, REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, BOOL fAddHead, IInternetHostSecurityManager *pHostSecurityManager);
int GetCountClientBindings() const { return m_pClientbinding.GetCount(); }
CClBinding* GetClientBinding() const { return m_pClientbinding.GetHead(); }
IBindStatusCallback* GetClientBSC() const { return (GetClientBinding())->GetAssBSC(); }
IBindCtx* GetClientBC() const { return (GetClientBinding())->GetAssBC(); }
REFCLSID GetClsid() const { return (GetClientBinding())->GetClsid(); }
CDownload* GetDownloadHead() const { return m_pDownloads.GetHead(); }
VOID AddDownloadToList(CDownload *pdl);
HRESULT FindDupCABInThread(IMoniker *pmk, CDownload **ppdlMatch); HRESULT FindCABInDownloadList(LPCWSTR szURL, CDownload *pdlHint, CDownload **ppdlMatch);
VOID CompleteOne(CDownload *pdl, HRESULT hrOSB, HRESULT hrStatus, HRESULT hrResponseHdr, LPCWSTR szError);
VOID CompleteAll(HRESULT hr, LPCWSTR szError);
STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
HRESULT ProcessHooks(CDownload *pdl); HRESULT ProcessHookSection(LPCSTR lpCurHook, CDownload *pdl);
HRESULT GetSatelliteName( LPSTR lpCurCode, int iLen);
BOOL IsSectionInINF(LPCSTR lpCurCode);
HRESULT GetInfCodeLocation( LPCSTR lpCurCode, LPSTR szURL);
HRESULT GetInfSectionInfo( LPSTR lpCurCode, int iLen, LPSTR szURL, LPCLSID *plpClsid, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS, DESTINATION_DIR *pdest, LPDWORD pdwRegisterServer, LPDWORD pdwCopyFlags, BOOL *pbDestDir );
HRESULT SetupInf(const char *szInf, char *szInfBaseName,CDownload *pdl);
VOID ProcessInf(CDownload *pdl);
HRESULT ParseOSD(const char *szOSD, char *szOSDBaseName, CDownload *pdl);
HRESULT QueueModuleUsage( LPCSTR szFileName, LONG muFlags); HRESULT UpdateModuleUsage();
HRESULT StartDownload( LPSTR szCurCode, CDownload *pdl, LPSTR szURL, DESTINATION_DIR dest, LPSTR szDestDir, DWORD dwRegisterServer, DWORD dwCopyFlags, CList <CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL);
BOOL HaveManifest() {return (HaveInf() || GetOSD());}
BOOL NeedToReboot() const {return (m_flags & CD_FLAGS_NEED_REBOOT);} VOID SetRebootRequired() {m_flags |= CD_FLAGS_NEED_REBOOT;}
BOOL IsSilentMode() const {return (m_flags & CD_FLAGS_SILENTOPERATION);} VOID SetSilentMode() {m_flags |= CD_FLAGS_SILENTOPERATION;}
BOOL IsAllTrusted() const {return ((m_flags & CD_FLAGS_TRUST_SOME_FAILED) == 0);} VOID SetTrustSomeFailed() {m_flags |= CD_FLAGS_TRUST_SOME_FAILED;}
BOOL ForceDownload() const {return (m_flags & CD_FLAGS_FORCE_DOWNLOAD);}
BOOL HaveInf() const {return (m_flags & CD_FLAGS_HAVE_INF);} VOID SetHaveInf() {m_flags |= CD_FLAGS_HAVE_INF;}
BOOL UsedCodeURL() const {return (m_flags & CD_FLAGS_USED_CODE_URL);} VOID SetUsedCodeURL() {m_flags |= CD_FLAGS_USED_CODE_URL;}
BOOL SafeToAbort() const {return ((m_flags & CD_FLAGS_UNSAFE_ABORT) == 0);} VOID SetUnsafeToAbort() {m_flags |= CD_FLAGS_UNSAFE_ABORT;}
BOOL BitsInCache() const {return (m_flags & CD_FLAGS_BITS_IN_CACHE);} VOID SetBitsInCache() {m_flags |= CD_FLAGS_BITS_IN_CACHE;}
BOOL FakeSuccess() const {return (m_flags & CD_FLAGS_FAKE_SUCCESS);} VOID SetFakeSuccess() {m_flags |= CD_FLAGS_FAKE_SUCCESS;}
HRESULT HandleUnSafeAbort();
BOOL NeedObject() const {return (m_flags & CD_FLAGS_NEED_CLASSFACTORY);} VOID SetNeedObject(DWORD fl) { m_flags |= (fl & CD_FLAGS_NEED_CLASSFACTORY);}
BOOL UseCodebaseOnly() const {return (m_flags & CD_FLAGS_USE_CODEBASE_ONLY);} VOID SetUseCodebaseOnly(DWORD fl) { m_flags |= (fl & CD_FLAGS_USE_CODEBASE_ONLY);}
BOOL RelContextMk() {return (m_flags & CD_FLAGS_NEW_CONTEXT_MONIKER);} VOID MarkNewContextMoniker() {m_flags |= CD_FLAGS_NEW_CONTEXT_MONIKER;} VOID ResetNewContextMoniker() {m_flags &= ~CD_FLAGS_NEW_CONTEXT_MONIKER;}
BOOL WaitingForEXE() {return (m_flags & CD_FLAGS_WAITING_FOR_EXE);} VOID SetNotWaitingForEXE() {m_flags &= ~CD_FLAGS_WAITING_FOR_EXE;}
BOOL UserCancelled() {return (m_flags & CD_FLAGS_USER_CANCELLED);} VOID SetUserCancelled() {m_flags |= CD_FLAGS_USER_CANCELLED;}
BOOL IsOnStack() const {return (m_flags & CD_FLAGS_ONSTACK);} BOOL SetOnStack() { if (IsOnStack()) { return FALSE; } else { m_flags |= CD_FLAGS_ONSTACK; return TRUE; } }
VOID ResetOnStack() {m_flags &= ~CD_FLAGS_ONSTACK;}
BOOL SkipDeclinedListCheck() const {return (m_flags & CD_FLAGS_SKIP_DECLINED_LIST_CHECK);}
BOOL DeleteEXEWhenDone() {return (m_flags & CD_FLAGS_DELETE_EXE);} VOID SetDeleteEXEWhenDone() {m_flags |= CD_FLAGS_DELETE_EXE;} VOID ResetDeleteEXEWhenDone() {m_flags &= ~CD_FLAGS_DELETE_EXE;}
HRESULT SetWaitingForEXE(LPCSTR szStatusText, BOOL bDeleteEXEWhenDone); VOID SetWaitingForEXEHandle(HANDLE hEXE) {m_pi.hProcess = hEXE;}
LPSTR GetDestDirHint() const { return m_plci->lpDestDir;} BOOL LocalVersionPresent() const { return m_plci->IsPresent();} FILETIME * GetLastModifiedTime() { return m_plci->GetLastModifiedTime();}
VOID InitLastModifiedFromDistUnit();
IMoniker* GetContextMoniker() const {return m_pmkContext;} VOID SetContextMoniker(IMoniker* pmk) {m_pmkContext = pmk;}
ICodeInstall* GetICodeInstall() const { return GetClientBinding()->GetICodeInstall(); }
LPCWSTR GetMainURL() const { return m_url;} LPCWSTR GetMainDistUnit() const { return m_szDistUnit;} LPCWSTR GetMainType() const { return m_szType;} LPCWSTR GetMainExt() const { return m_szExt;}
LPCSTR GetCacheDir() const { return m_szCacheDir;} HRESULT ResolveCacheDirNameConflicts();
void SetExactVersion(BOOL bExactVersion) { m_bExactVersion = bExactVersion; if (m_bExactVersion) { m_bUninstallOld = TRUE; // implied
} }
VOID SetListCookie(LISTPOSITION pos) {m_ListCookie = pos;} LISTPOSITION GetListCookie() const {return m_ListCookie;}
HRESULT AcquireSetupCookie(); HRESULT RelinquishSetupCookie();
HRESULT PiggybackDupRequest( IBindStatusCallback *pDupClientBSC, IBindCtx *pbc, REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID riid);
BOOL GenerateErrStrings(HRESULT hr, char **ppszErrMsg, WCHAR **ppwszError);
static HRESULT CCodeDownload::AnyCodeDownloadsInThread();
static HRESULT CCodeDownload::HasUserDeclined( LPCWSTR szDistUnit, LPCWSTR szType, LPCWSTR szExt, IBindStatusCallback *pClientBSC, IInternetHostSecurityManager *pHostSecurityManager);
static HRESULT CCodeDownload::HandleDuplicateCodeDownloads( LPCWSTR szURL, LPCWSTR szType, LPCWSTR szExt, REFCLSID rclsid, LPCWSTR szDistUnit, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, IBindCtx* pbc, IBindStatusCallback *pDupClientBSC, DWORD dwFlags, IInternetHostSecurityManager *pHostSecurityManager);
HRESULT CCodeDownload::SetUserDeclined();
HRESULT IsDuplicateHook(LPCSTR szHook); HRESULT IsDuplicateJavaSetup( LPCWSTR szPackage);
HRESULT ProcessJavaManifest(IXMLElement *pJava, const char *szOSD, char *szOSDBaseName, CDownload *pdl); HRESULT ProcessDependency(CDownload *pdl, IXMLElement *pDepend); HRESULT ProcessNativeCode(CDownload *pdl, IXMLElement *pCode); HRESULT ExtractInnerCAB(CDownload *pdl, LPSTR szCABFile); HRESULT AddDistUnitList(LPWSTR szDistUnit);
VOID DoSetup();
HRESULT DealWithExistingFile( LPSTR szExistingFile, DWORD cbExistingFile, LPSTR pBaseExistingName, LPSTR *ppDestDir, LPDWORD pdwLocFVMS, LPDWORD pdwLocFVLS, FILETIME *pftLastModified = NULL);
BOOL NeedLatestVersion() { return (( m_dwFileVersionMS == -1) && (m_dwFileVersionLS == -1)); } LPSTR GetEtag() { return m_pbEtag;} VOID SetEtag(LPSTR szEtag) { m_pbEtag = szEtag;} LPSTR GetLocalVersionEtag() { return m_plci->GetLocalVersionEtag();}
LPSTR GetLastMod() { return m_szLastMod[0]?m_szLastMod:NULL;} VOID SetLastModifiedTime(LPCSTR szLastMod) { lstrcpy(m_szLastMod, szLastMod); }
HRESULT DelayRegisterOCX(LPCSTR pszSrcFileName, FILEXTN extn);
HRESULT InstallOCX(LPCSTR lpSrcFileName, FILEXTN extn, BOOL fLocalServer); HRESULT RegisterPEDll( LPCSTR lpSrcFileName);
#ifdef WX86
HRESULT RegisterWx86Dll( LPCSTR lpSrcFileName); CMultiArch *GetMultiArch() { return &m_MultiArch; } #endif
// BUGBUG: put these three in a SearchPath class
HRESULT SetupCODEUrl(LPWSTR *ppDownloadURL, FILEXTN *pextn);
HRESULT GetNextComponent( LPSTR szList, LPSTR *ppCur);
HRESULT GetNextOnInternetSearchPath( REFCLSID rclsid, HGLOBAL *phPostData, DWORD *pcbPostData, LPWSTR szURL, DWORD dwSize, LPWSTR *ppDownloadURL, FILEXTN *pextn);
HRESULT SelfRegEXETimeout();
HRESULT AbortBinding(CClBinding *pbinding);
BOOL WeAreReadyToSetup();
LPCSTR GetMainInf() { return m_szInf;} LPCSTR GetOSD() { return m_szOSD;} LCID GetLCID() { return m_lcid;}
BOOL VersionFromManifest(LPSTR szVersionInManifest, int iLen);
HRESULT SetManifest(FILEXTN extn, LPCSTR szManifest);
CLangInfo *GetLangInfo() { return &m_langinfo;} void CodeDownloadDebugOut(int iOption, BOOL fOperationFailed, UINT iResId, ...);
HRESULT IsPackageLocallyInstalled(LPCWSTR szPackageName, LPCWSTR szNameSpace, DWORD dwVersionMS, DWORD dwVersionLS);
IJavaPackageManager * GetPackageManager() { return m_pPackageManager;} HRESULT SetCatalogFile(LPSTR szCatalogFile); LPSTR GetCatalogFile(); HRESULT SetMainCABJavaTrustPermissions(PJAVA_TRUST pbJavaTrust); PJAVA_TRUST GetJavaTrust(); void SetDebugLog(CDLDebugLog * debuglog); void SetCatalogInstalled() { m_bCatalogInstalled = TRUE; }
BOOL IsCatalogInstalled() { return m_bCatalogInstalled; }
void SetAtom(ATOM atom) { if(m_atom) DeleteAtom(m_atom); m_atom = atom; } HRESULT VerifyFileAgainstSystemCatalog(LPCSTR pFileName, LPWSTR pwszFullCatalogPath, DWORD* pdwBuffer) { return m_wvt.VerifyFileAgainstSystemCatalog(pFileName, pwszFullCatalogPath, pdwBuffer); }
BOOL FileProtectionCheckSucceeded(LPCSTR lpszExistingFileName);
BOOL IsFileProtected(LPCSTR pFileName);
private:
CDL_STATE GetState() const { return m_state;} VOID SetState(CDL_STATE state) { m_state = state;}
HRESULT UpdateFileList(HKEY hKeyContains); HRESULT UpdateDependencyList(HKEY hKeyContains); HRESULT UpdateJavaList(HKEY hKeyContains); HRESULT UpdateDistUnit(CLocalComponentInfo *plci); HRESULT UpdateLanguageCheck(CLocalComponentInfo *plci);
void DumpDebugLog(char *szCacheFileName, LPTSTR szErrorMsg, HRESULT hrError); void DestroyPCBHList(CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList);
DWORD m_cRef;
CDL_STATE m_state; // state of code download
LPWSTR m_url; LPWSTR m_szDistUnit; LPWSTR m_szType; LPWSTR m_szExt; LPSTR m_szDisplayName; LPSTR m_szVersionInManifest;
IMoniker* m_pmkContext; // first download's pmk
// becomes the context
// for handling subsequent
// relative URLs
DWORD m_dwFileVersionMS; // little quirky that
DWORD m_dwFileVersionLS; // this really the primary
// control's fileversion
// can really be something
// else if deemed appropriate
// eg: subversion of clsid
LCID m_lcid; // cache lcid client needs
// this is pulled out of the
// bindctx (BIND_OPTS2)
CList<CModuleUsage*,CModuleUsage*> // linked list of module usage
m_ModuleUsage; // entries to add
CList<CClBinding*,CClBinding*> // linked list of client
m_pClientbinding; // IBindings
CList<CDownload*,CDownload*> // linked list of CDownload
m_pDownloads; // pieces
CList<LPWSTR,LPWSTR> // linked list of dependent
m_pDependencies; // distribution units
DWORD m_flags; // provision for hacks :)
// used internally now to
// mark if we have an INF file
// and if safe to abort
LPSTR m_szInf; // INF filename if one exists
LPSTR m_szOSD; // INF filename if one exists
LPSTR m_szCacheDir; // OCCACHE dir that is setup
// for each code download
// is usually = g_szOCXCacheDir
// but if a name conflict arises
// it can be OCCACHE\CONFLICT.n
LPSTR m_pAddCodeSection; // Add.Code section in INF
// bunch of null terminated
// strings, last one double
// null terminated (like env)
LPSTR m_pCurCode; // points at what ProcessInf
// is pending processing
HKEY m_hKeySearchPath; // key to REGSTR_PATH_ISP
LPSTR m_pSearchPath; // List of searchpath comps
LPSTR m_pSearchPathNextComp; // pointer into list above at
// current component
CLangInfo m_langinfo;
LPSTR m_szWaitForEXE; // str that points to name of
// self registering EXE that we
// are waiting now to complete
// This is used to give
// detailed CodeInstallProblem
// when we get a ClientBinding::
// Abort wahile waiting for an
// EXE to complete setup/reg
PROCESS_INFORMATION m_pi; // PI for the currently self-
// registering EXE that we
// are running
LISTPOSITION m_ListCookie; // cookie to remove this
// download from the per-thread
// list of CCodeDownload's in
// progress (CList)
HRESULT m_hr; // hr to pass to CompleteAll
// this store away the first
// real failure code in a
// multipart code download
char m_szLastMod[INTERNET_RFC1123_BUFSIZE+1]; // last modified date of the
// main URL (typically CODEBASE
// or the URL redirected by
// Object Index). We save this
// with the dist unit DB to use
// later for Get Latest.
DWORD m_dwExpire; // number of days before DU eligible
// for scavenging.
DWORD m_dwSystemComponent;
char *m_pbEtag;
CLocalComponentInfo* m_plci;
IJavaPackageManager* m_pPackageManager; // Java pkg mgr
DWORD m_grfBINDF; CList<CCodeBaseHold *, CCodeBaseHold *> *m_pcbhList; LPSTR m_szCatalogFile; BOOL m_bCatalogInstalled; ATOM m_atom; PJAVA_TRUST m_pbJavaTrust; CDLDebugLog * m_debuglog;
BOOL m_bUninstallOld; BOOL m_bExactVersion; HMODULE m_hModSFC;
Cwvt m_wvt;
#ifdef WX86
CMultiArch m_MultiArch; #endif
};
class DebugLogElement { public: DebugLogElement() : m_szMessage(NULL) {} DebugLogElement(LPSTR szMessage); DebugLogElement(const DebugLogElement &ref); virtual ~DebugLogElement();
public: LPCSTR GetLogMessage() { return m_szMessage; } HRESULT SetLogMessage(LPSTR szMessage);
private: LPSTR m_szMessage; };
// Class to make a debug log and pass out error messages
// Note reguarding wide strings vs. ANSI:
// For file-write compatiblity, the private strings of CDLDebugLog
// are stored as multibyte, but the primary accessors (the private
// variables in CCodeDownLoad) are wide characters. Hence, the
// return values for the accesors are Multibyte, since these are used
// primarily by this class, while the set parameters are wide character
class CDLDebugLog { public: ~CDLDebugLog();
// Name accessor functions
// Return the current value for the requested name (may be "")
LPCTSTR GetMainClsid() {return m_szMainClsid;} LPCTSTR GetMainType() {return m_szMainType;} LPCTSTR GetMainExt() {return m_szMainExt;} LPCTSTR GetMainUrl() {return m_szMainUrl;} LPCTSTR GetFileName() {return m_szFileName;} LPCTSTR GetUrlName() {return m_szUrlName;}
// Functions to access or output error messages
void DebugOut(int iOption, BOOL fOperationFailed, UINT iResId, ...); void DebugOutPreFormatted(int iOption, BOOL fOperationFailed, LPTSTR szDebugString); void DumpDebugLog(LPTSTR pszCacheFileName, int cbBufLen, LPTSTR szErrorMsg, HRESULT hrError);
// Deletion and Initialization functions
void Clear(); BOOL Init(CCodeDownload * pcdl); BOOL Init(LPCWSTR wszMainClsid, LPCWSTR wszMainType, LPCWSTR wszMainExt, LPCWSTR wszMainUrl); void MakeFile();
// Static functions for storing and accessing stored debug logs
static void AddDebugLog(CDLDebugLog * dlog); static void RemoveDebugLog(CDLDebugLog * dlog); static CDLDebugLog * GetDebugLog(LPCWSTR wszMainClsid, LPCWSTR wszMainType, LPCWSTR wszMainExt, LPCWSTR wszMainUrl); // Static functions for saving an error message for the download
static BOOL SetSavedMessage(LPCTSTR szMessage, BOOL bOverwrite); static LPCTSTR GetSavedMessage();
// Static function for debug log construction
static CDLDebugLog * MakeDebugLog();
// Com-type add and release functions
int AddRef(); int Release();
private:
CDLDebugLog(); CList<DebugLogElement *, DebugLogElement *> m_DebugLogList; BOOL m_fAddedDebugLogHead; TCHAR m_szFileName[INTERNET_MAX_URL_LENGTH]; TCHAR m_szUrlName[INTERNET_MAX_URL_LENGTH]; TCHAR m_szMainClsid[MAX_DEBUG_STRING_LENGTH]; TCHAR m_szMainType[MAX_DEBUG_STRING_LENGTH]; TCHAR m_szMainExt[MAX_DEBUG_STRING_LENGTH]; TCHAR m_szMainUrl[INTERNET_MAX_URL_LENGTH];
// Support addref and release
int m_iRefCount;
// List and mutex for stored CDLDebugLog's
static CList<CDLDebugLog *, CDLDebugLog *> s_dlogList; static CMutexSem s_mxsDLogList; static CMutexSem s_mxsMessage;
// Saved error message
static TCHAR s_szMessage[]; static BOOL s_bMessage;
};
// values for CDownload::m_flags
typedef enum { DL_FLAGS_INIT = 0x0, DL_FLAGS_TRUST_VERIFIED= 0x1, DL_FLAGS_EXTRACT_ALL= 0x2, DL_FLAGS_CDL_PROTOCOL= 0x4 // using cdl:// to kick off DL
} DL_FLAGS;
class CParentCDL {
public:
CParentCDL(CCodeDownload *pcdl) {m_pcdl = pcdl;m_bCompleteSignalled = FALSE;}
CCodeDownload* m_pcdl; BOOL m_bCompleteSignalled; };
class CBindStatusCallback; class CSetupHook;
// one for each individual downloads
class CDownload {
public:
// constructor
CDownload(LPCWSTR szURL, FILEXTN extn, HRESULT *phr); ~CDownload();
void CDownload::CleanUp();
HRESULT AddParent(CCodeDownload *pcdl); HRESULT ReleaseParent(CCodeDownload *pcdl);
HRESULT CompleteSignal(HRESULT hrOSB, HRESULT hrStatus, HRESULT hrResponseHdr, LPCWSTR szError);
HRESULT DoDownload(LPMONIKER *ppmkContext, DWORD grfBINDF, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL);
HRESULT Abort(CCodeDownload *pcdl);
BOOL IsSignalled(CCodeDownload *pcdl);
// for each in list CSetup::DoSetup
HRESULT DoSetup();
BOOL IsDuplicateSetup(LPCSTR pBaseFileName);
// called by CBSC::OnStopBinding as soon as the binding completes
VOID ProcessPiece();
// for each in list CSetup::CheckForNameCollision
HRESULT CheckForNameCollision(LPCSTR szCacheDir);
HRESULT CleanupFiles();
CDownload *GetNext() const { return m_pdlnext;} VOID SetNext(CDownload *pdlnext) { m_pdlnext = pdlnext;}
CSetup* GetSetupHead() const {return m_pSetuphead;} VOID AddSetupToList(CSetup *pSetup); HRESULT RemoveSetupFromList(CSetup *pSetup);
HRESULT AddHook( LPCSTR szHook, LPCSTR szInf, LPCSTR szInfSection, DWORD flags);
HRESULT AddSetupToExistingCAB( char *lpCode, const char * szDestDir, DESTINATION_DIR dest, DWORD dwRegisterServer, DWORD dwCopyFlags);
CCodeDownload* GetCodeDownload() const { return (m_ParentCDL.GetHead())->m_pcdl;}
CBindStatusCallback* GetBSC() const { return m_pbsc;} IBindCtx* GetBindCtx() const { return m_pbc;}
VOID SetUnkForCacheFileRelease(IUnknown *pUnk) {m_pUnkForCacheFileRelease = pUnk;}
LPCSTR GetFileName() const { return m_pFileName;} VOID SetFileName(LPSTR pFileName) { m_pFileName = pFileName;}
HRESULT IsDownloadedVersionRequired();
LPCWSTR GetURL() const { return m_url;}
HRESULT GetFriendlyName(LPSTR szUrlPath, LPSTR *ppBaseFileName);
IMoniker* GetMoniker() const {return m_pmk;}
HRESULT SetURLAndExtn(LPCWSTR szURL, FILEXTN extn);
HRESULT SniffType();
FILEXTN GetExtn() const {return m_extn;} PFNAME GetFilesToExtract() const { return m_pFilesToExtract;}
DLSTATE GetDLState() const { return m_state;} VOID SetDLState(DLSTATE state) { m_state = state; }
VOID SetProgress(ULONG ulProgress, ULONG ulProgressMax) { m_ulProgress = ulProgress; m_ulProgressMax = ulProgressMax;} VOID SumProgress(ULONG *pulProgress, ULONG *pulProgressMax) { *pulProgress += m_ulProgress; *pulProgressMax += m_ulProgressMax;}
PSESSION GetSession() const { return m_psess;} VOID SetSession(PSESSION psess) { m_psess = psess;}
HGLOBAL GetPostData(DWORD *pcbPostData) const { *pcbPostData = m_cbPostData; return m_hPostData; }
VOID SetPostData(HGLOBAL hPostData, DWORD cbPostData) { m_hPostData = hPostData; m_cbPostData = cbPostData; } BOOL DoPost() const { return (m_hPostData != NULL);}
HRESULT GetResponseHeaderStatus() const {return m_hrResponseHdr;} VOID SetResponseHeaderStatus( HRESULT hrResponseHdr) { m_hrResponseHdr = hrResponseHdr;}
VOID VerifyTrust();
BOOL TrustVerified() const {return (m_flags & DL_FLAGS_TRUST_VERIFIED);} VOID SetTrustVerified() {m_flags |= DL_FLAGS_TRUST_VERIFIED;}
BOOL NeedToExtractAllFiles() const {return(m_flags & DL_FLAGS_EXTRACT_ALL);} VOID SetNeedToExtractAll() {m_flags |= DL_FLAGS_EXTRACT_ALL;}
BOOL UsingCdlProtocol() const {return(m_flags & DL_FLAGS_CDL_PROTOCOL);} HRESULT SetUsingCdlProtocol(LPWSTR szDistUnit); LPWSTR GetDistUnitName() const {return(m_wszDistUnit);}
HRESULT ExtractManifest(FILEXTN extn, LPSTR szFileName, LPSTR& pBaseFileName);
CSetupHook* FindHook(LPCSTR szHook); CJavaSetup* FindJavaSetup(LPCWSTR szPackageName);
HRESULT AddJavaSetup(LPCWSTR szPackageName, LPCWSTR szNameSpace, IXMLElement *pPackage, DWORD dwVersionMS, DWORD dwVersionLS, DWORD flags); CList<CJavaSetup*,CJavaSetup*> *GetJavaSetupList() { return &m_JavaSetupList;} BOOL HasJavaPermissions(); BOOL HasAllActiveXPermissions(); PJAVA_TRUST GetJavaTrust() {return m_pbJavaTrust;}
HRESULT PerformVirusScan(LPSTR szFileName);
STDMETHODIMP DownloadRedundantCodeBase(); HRESULT SetMainCABJavaTrustPermissions(PJAVA_TRUST pbJavaTrust);
void SetExactVersion(BOOL bFlag) {m_bExactVersion = bFlag;}
private:
LPWSTR m_url; FILEXTN m_extn; LPSTR m_pFileName; // filename in temp once downloaded
IMoniker* m_pmk; IBindCtx* m_pbc;
IUnknown* m_pUnkForCacheFileRelease;
CBindStatusCallback* m_pbsc;
CDownload* m_pdlnext;
CList<CParentCDL *,CParentCDL *> // linked list of CCodeDownloads
m_ParentCDL; // that have interest in us
ULONG m_ulProgress; ULONG m_ulProgressMax;
DLSTATE m_state;
PSESSION m_psess; // CAB extraction struc
PFNAME m_pFilesToExtract; // applicable only for CAB objs
CSetup* m_pSetuphead; // list of CSetup's for this dwld
DWORD m_flags; // provision for hacks :)
HGLOBAL m_hPostData; // has the query for the clsid
DWORD m_cbPostData; // has size of post data
BOOL m_bCompleteSignalled;
LPWSTR m_wszDistUnit; // name of distribution for cdl:// dl
HRESULT m_hrOSB; // this is the hr we got
// from OnStopBinding
HRESULT m_hrStatus; // this is the hr we got
// URLMON for the binding
HRESULT m_hrResponseHdr; // this is the hr we got
// from the response headers
// when querying for this clsid
// this is to make sure we have the
// right error status even when
// urlmon does not pass back right
// OnError.
PJAVA_TRUST m_pbJavaTrust;
CList<CSetupHook*,CSetupHook*> // linked list of setup hooks
m_SetupHooks;
CList<CJavaSetup*,CJavaSetup*> // linked list of Java setups
m_JavaSetupList;
Cwvt m_wvt; // WinVerifyTrust delay load
// magic in this class
CList<CCodeBaseHold *, CCodeBaseHold *> *m_pcbhList; DWORD m_grfBINDF; LPMONIKER *m_ppmkContext;
BOOL m_bExactVersion;
};
// BSC for our indiv. CDownloads
class CBindStatusCallback : public IBindStatusCallback ,public IHttpNegotiate ,public IWindowForBindingUI ,public IServiceProvider ,public ICatalogFileInfo {
public:
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid,void ** ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release();
// IBindStatusCallback methods
STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindinfo); STDMETHODIMP OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pFmtetc, STGMEDIUM __RPC_FAR *pstgmed); STDMETHODIMP OnObjectAvailable( REFIID riid, IUnknown* punk);
STDMETHODIMP OnStartBinding(DWORD grfBSCOPTION,IBinding* pbinding); STDMETHODIMP GetPriority(LONG* pnPriority); STDMETHODIMP OnLowResource(DWORD dwReserved); STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText); STDMETHODIMP OnStopBinding(HRESULT hrResult, LPCWSTR szError);
// *** IHttpNegotiate methods ***
STDMETHOD(BeginningTransaction) ( LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders);
STDMETHOD(OnResponse) ( DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders);
// *** IWindowForBindingUI methods ***
STDMETHOD(GetWindow) ( REFGUID rguidreason, HWND *phWnd);
// *** IServiceProvider ***
STDMETHOD(QueryService) ( REFGUID guidService, REFIID riid, LPVOID *ppv);
// *** ICatalogFileInfo ***
STDMETHODIMP GetCatalogFile(LPSTR *ppszCatalogFile); STDMETHODIMP GetJavaTrust(void **ppJavaTrust);
// constructor
CBindStatusCallback(CDownload *pdl, DWORD grfBINDF); ~CBindStatusCallback();
IBinding* GetBinding() const {return m_pbinding;}
private:
DWORD m_cRef; IBinding* m_pbinding; CDownload* m_pdl; // point up into download obj
DWORD m_grfBINDF;
BYTE m_cbBuffer[BUFFERMAX];
};
class CSetupHook { public:
CSetupHook( CDownload *pdl, LPCSTR szHook, LPCSTR szInf, LPCSTR szInfSection, DWORD flags, HRESULT *phr);
~CSetupHook();
HRESULT Run();
static HRESULT ExpandCommandLine( LPSTR szSrc, LPSTR szBuf, DWORD cbBuffer, const char * szVars[], // array of variable names eg. %EXTRACT_DIR%
const char * szValues[]); // corresponding values to expand of vars
static HRESULT ExpandVar( LPSTR& pchSrc, // passed by ref!
LPSTR& pchOut, // passed by ref!
DWORD& cbLen, // passed by ref!
DWORD cbBuffer, // size of out buffer
const char * szVars[], // array of variable names eg. %EXTRACT_DIR%
const char * szValues[]);// corresponding values to expand of vars
HRESULT TranslateString();
INSTALL_STATE GetState() const { return m_state;} VOID SetState(INSTALL_STATE state) { m_state = state;}
LPSTR GetHookName() { return m_szHook; }
const char * GetObjectDir() {
if (m_pdl && m_pdl->GetCodeDownload()) return m_pdl->GetCodeDownload()->GetCacheDir(); else return NULL; }
LPCWSTR GetSrcURL() { if (m_pdl) { return m_pdl->GetURL(); } else { return NULL; } }
LPSTR GetHookDir() {
if (m_pdl && m_pdl->GetSession()) return m_pdl->GetSession()->achLocation; else return NULL; }
private:
INSTALL_STATE m_state; // state of install operation
CDownload* m_pdl; LPSTR m_szHook; LPSTR m_szInf; LPSTR m_szInfSection; DWORD m_flags; };
HRESULT SetCodeDownloadTLSVars();
// private helpers
// from isctrl.cxx
HRESULT IsControlLocallyInstalled( LPSTR lpCurCode, const LPCLSID lpclsid, LPCWSTR szDistUnit, DWORD dwFileVersionMS, DWORD dwFileVersionLS, CLocalComponentInfo *plci, LPSTR szDestDirHint, BOOL bExactVersion = FALSE);
// from isctrl.cxx
HRESULT IsCLSIDLocallyInstalled( LPSTR lpCurCode, const LPCLSID lpclsid, LPCWSTR szDistUnit, DWORD dwFileVersionMS, DWORD dwFileVersionLS, CLocalComponentInfo *plci, LPSTR szDestDirHint, HRESULT *pHrExtra, BOOL bExactVersion );
HRESULT IsDistUnitLocallyInstalled( LPCWSTR szDistUnit, DWORD dwFileVersionMS, DWORD dwFileVersionLS, CLocalComponentInfo *plci, LPSTR szDestDirHint, LPBOOL pbParanoidCheck, DWORD flags);
HRESULT IsPackageLocallyInstalled( IJavaPackageManager **ppPackageManager, LPCWSTR szPackageName, LPCWSTR szNameSpace, DWORD dwVersionMS, DWORD dwVersionLS);
HRESULT LocalVersionOK( HKEY hkeyClsid, CLocalComponentInfo *plci, DWORD dwFileVersionMS, DWORD dwFileVersionLS, BOOL bExactVersion );
HRESULT GetFileVersion( CLocalComponentInfo *plci, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS);
HRESULT GetVersionFromString( const char *szBuf, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS, char cSeperator = ',');
BOOL AdviseForceDownload( const LPCLSID lpclsid, DWORD dwClsContext);
// flags for UpdateModuleUsage
#define MU_CLIENT 0 // mark us as a client
#define MU_OWNER 1 // mark us as the owner (iff no prev ver exists)
HRESULT UpdateModuleUsage( LPCSTR szFileName, LPCSTR szClientName, LPCSTR szClientPath, LONG muFlags);
HRESULT UpdateSharedDlls( LPCSTR szFileName);
BOOL SupportsSelfRegister(LPSTR szFileName); BOOL WantsAutoExpire(LPSTR szFileName, DWORD *pnExpireDays );
// from wvt.cxx
HRESULT GetActivePolicy(IInternetHostSecurityManager* pZoneManager, LPCWSTR pwszZone, DWORD dwUrlAction, DWORD& dwPolicy, BOOL fEnforceRestricted);
// from peldr.cxx
HRESULT IsCompatibleFile(const char *szFileName, LPDWORD lpdwMachineType=NULL); HRESULT IsRegisterableDLL(const char *szFileName);
// fro, softdist.cxx
HRESULT GetLangString(LCID localeID, char *szThisLang, int iLen); HRESULT InitBrowserLangStrings();
// from duman.cxx
HRESULT GetSoftDistFromOSD(LPCSTR szFile, IXMLElement **ppSoftDist);
HRESULT GetFirstChildTag(IXMLElement *pRoot, LPCWSTR szTag, IXMLElement **ppChildReq); HRESULT GetNextChildTag(IXMLElement *pRoot, LPCWSTR szTag, IXMLElement **ppChildReq, int &nLastChild);
HRESULT GetAttribute(IXMLElement *pElem, LPWSTR szAttribName, VARIANT *pvProp); HRESULT GetAttributeA(IXMLElement *pElem, LPWSTR szAttribName, LPSTR pAttribValue, DWORD dwBufferLen); HRESULT DupAttributeA(IXMLElement *pElem, LPWSTR szAttribName, LPSTR *ppszRet); HRESULT DupAttribute(IXMLElement *pElem, LPWSTR szAttribName, LPWSTR *ppszRet); HRESULT GetTextContent(IXMLElement *pRoot, LPCWSTR szTag, LPWSTR *ppszContent);
// from jit.cxx
HRESULT GetIEFeatureFromMime(LPWSTR *ppwszIEFeature, LPCWSTR pwszMimeType, QUERYCONTEXT *pQuery, QUERYCONTEXT *pQueryRec=NULL); HRESULT GetIEFeatureFromClass(LPWSTR *ppwszIEFeature, REFCLSID clsid, QUERYCONTEXT *pQuery, QUERYCONTEXT *pQueryRec=NULL);
// from client.cxx
IInternetHostSecurityManager* GetHostSecurityManager(IBindStatusCallback *pclientbsc);
// from helpers.cxx
HRESULT CheckFileImplementsCLSID(const char *pszFileName, REFCLSID rClsid); FILEXTN GetExtnAndBaseFileName( char *szName, char **plpBaseFileName); HRESULT MakeUniqueTempDirectory(LPCSTR szTempDir, LPSTR szUniqueTempDir, int iLen); HRESULT ComposeHackClsidFromMime(LPSTR szHackMimeType, int iLen, LPCSTR szClsid);
HRESULT GetHeaderValue ( LPCWSTR szResponseHeadersBuffer, DWORD cbResponseHeadersBuffer, LPCWSTR lpcszHeaderName, LPWSTR pHeaderValue, DWORD cbHeaderValue);
HRESULT GetClsidFromExtOrMime( REFCLSID rclsid, CLSID &clsidout, LPCWSTR szExt, LPCWSTR szTYPE, LPSTR *ppFileName);
STDAPI AsyncGetClassBitsEx( REFCLSID rclsid, // CLSID
CodeDownloadData * pcdd, // Contains requested object's descriptors
IBindCtx *pbc, // bind ctx: should contain BSC
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid); // Usually IID_IClassFactory
STDAPI AsyncGetClassBits2Ex( LPCWSTR szClientID, // client ID, root object if NULL
CodeDownloadData * pcdd, // Contains requested object's descriptors
IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
IUnknown **pUnk);
STDAPI AsyncInstallDistributionUnitEx( CodeDownloadData * pcdd, // Contains requested object's descriptors
IBindCtx *pbc, // bind ctx
REFIID riid, IUnknown **pUnk, LPVOID pvReserved); // Must be NULL
// backwards compatability
STDAPI AsyncGetClassBits( REFCLSID rclsid, // CLSID
LPCWSTR szType, // MIME type
LPCWSTR szExtension, // or Extension
// as alternate
// if CLSID == CLSID_NULL
DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODEBASE= in OBJECT tag
IBindCtx *pbc, // bind ctx: should contain BSC
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags); STDAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE, LPCWSTR szExt, DWORD dwFileVersionMS, // CODEBASE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODEBASE
IBindCtx *pbc, // bind ctx
LPVOID pvReserved, // Must be NULL
DWORD flags); STDAPI AsyncGetClassBits2( LPCWSTR szClientID, // client ID, root object if NULL
LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
LPCWSTR szTYPE, LPCWSTR szExt, DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODE= in INSERT tag
IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags);
#ifdef unix
extern "C" #endif /* unix */
STDAPI_(DWORD) CDLGetLongPathNameA( LPSTR lpszLong, LPCSTR lpszShort, DWORD cchBuffer );
#ifdef unix
extern "C" #endif /* unix */
STDAPI_(DWORD) CDLGetLongPathNameW( LPWSTR lpszLongPath, LPCWSTR lpszShortPath, DWORD cchBuffer );
HRESULT GetActiveXSafetyProvider( IActiveXSafetyProvider **ppProvider );
extern int g_CPUType; extern BOOL g_fRunningOnNT; extern BOOL g_bNT5OrGreater; #ifdef WX86
extern BOOL g_fWx86Present; #endif
VOID DetermineOSAndCPUVersion();
#ifdef UNICODE
#define CDLGetLongPathName CDLGetLongPathNameW
#else
#define CDLGetLongPathName CDLGetLongPathNameA
#endif // !UNICODE
#endif /* end hide classes from 'C' */
#endif // _CDL_H_
|