00001 // **************************************************************************** 00002 // File: IASIOThiscallResolver.h 00003 // Description: The IASIOThiscallResolver class implements the IASIO 00004 // interface and acts as a proxy to the real IASIO interface by 00005 // calling through its vptr table using the thiscall calling 00006 // convention. To put it another way, we interpose 00007 // IASIOThiscallResolver between ASIO SDK code and the driver. 00008 // This is necessary because most non-Microsoft compilers don't 00009 // implement the thiscall calling convention used by IASIO. 00010 // 00011 // iasiothiscallresolver.cpp contains the background of this 00012 // problem plus a technical description of the vptr 00013 // manipulations. 00014 // 00015 // In order to use this mechanism one simply has to add 00016 // iasiothiscallresolver.cpp to the list of files to compile 00017 // and #include <iasiothiscallresolver.h> 00018 // 00019 // Note that this #include must come after the other ASIO SDK 00020 // #includes, for example: 00021 // 00022 // #include <windows.h> 00023 // #include <asiosys.h> 00024 // #include <asio.h> 00025 // #include <asiodrivers.h> 00026 // #include <iasiothiscallresolver.h> 00027 // 00028 // Actually the important thing is to #include 00029 // <iasiothiscallresolver.h> after <asio.h>. We have 00030 // incorporated a test to enforce this ordering. 00031 // 00032 // The code transparently takes care of the interposition by 00033 // using macro substitution to intercept calls to ASIOInit() 00034 // and ASIOExit(). We save the original ASIO global 00035 // "theAsioDriver" in our "that" variable, and then set 00036 // "theAsioDriver" to equal our IASIOThiscallResolver instance. 00037 // 00038 // Whilst this method of resolving the thiscall problem requires 00039 // the addition of #include <iasiothiscallresolver.h> to client 00040 // code it has the advantage that it does not break the terms 00041 // of the ASIO licence by publishing it. We are NOT modifying 00042 // any Steinberg code here, we are merely implementing the IASIO 00043 // interface in the same way that we would need to do if we 00044 // wished to provide an open source ASIO driver. 00045 // 00046 // For compilation with MinGW -lole32 needs to be added to the 00047 // linker options. For BORLAND, linking with Import32.lib is 00048 // sufficient. 00049 // 00050 // The dependencies are with: CoInitialize, CoUninitialize, 00051 // CoCreateInstance, CLSIDFromString - used by asiolist.cpp 00052 // and are required on Windows whether ThiscallResolver is used 00053 // or not. 00054 // 00055 // Searching for the above strings in the root library path 00056 // of your compiler should enable the correct libraries to be 00057 // identified if they aren't immediately obvious. 00058 // 00059 // Note that the current implementation of IASIOThiscallResolver 00060 // is not COM compliant - it does not correctly implement the 00061 // IUnknown interface. Implementing it is not necessary because 00062 // it is not called by parts of the ASIO SDK which call through 00063 // theAsioDriver ptr. The IUnknown methods are implemented as 00064 // assert(false) to ensure that the code fails if they are 00065 // ever called. 00066 // Restrictions: None. Public Domain & Open Source distribute freely 00067 // You may use IASIOThiscallResolver commercially as well as 00068 // privately. 00069 // You the user assume the responsibility for the use of the 00070 // files, binary or text, and there is no guarantee or warranty, 00071 // expressed or implied, including but not limited to the 00072 // implied warranties of merchantability and fitness for a 00073 // particular purpose. You assume all responsibility and agree 00074 // to hold no entity, copyright holder or distributors liable 00075 // for any loss of data or inaccurate representations of data 00076 // as a result of using IASIOThiscallResolver. 00077 // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from 00078 // Andrew Baldwin, and volatile for whole gcc asm blocks, 00079 // both for compatibility with newer gcc versions. Cleaned up 00080 // Borland asm to use one less register. 00081 // 1.3 Switched to including assert.h for better compatibility. 00082 // Wrapped entire .h and .cpp contents with a check for 00083 // _MSC_VER to provide better compatibility with MS compilers. 00084 // Changed Singleton implementation to use static instance 00085 // instead of freestore allocated instance. Removed ASIOExit 00086 // macro as it is no longer needed. 00087 // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to 00088 // allow them to be embedded in expressions (if statements). 00089 // Cleaned up some comments. Removed combase.c dependency (it 00090 // doesn't compile with BCB anyway) by stubbing IUnknown. 00091 // 1.1 Incorporated comments from Ross Bencina including things 00092 // such as changing name from ThiscallResolver to 00093 // IASIOThiscallResolver, tidying up the constructor, fixing 00094 // a bug in IASIOThiscallResolver::ASIOExit() and improving 00095 // portability through the use of conditional compilation 00096 // 1.0 Initial working version. 00097 // Created: 6/09/2003 00098 // Authors: Fraser Adams 00099 // Ross Bencina 00100 // Rene G. Ceballos 00101 // Martin Fay 00102 // Antti Silvast 00103 // Andrew Baldwin 00104 // 00105 // **************************************************************************** 00106 00107 00108 #ifndef included_iasiothiscallresolver_h 00109 #define included_iasiothiscallresolver_h 00110 00111 // We only need IASIOThiscallResolver at all if we are on Win32. For other 00112 // platforms we simply bypass the IASIOThiscallResolver definition to allow us 00113 // to be safely #include'd whatever the platform to keep client code portable 00114 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 00115 00116 00117 // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver 00118 // is not used. 00119 #if !defined(_MSC_VER) 00120 00121 00122 // The following is in order to ensure that this header is only included after 00123 // the other ASIO headers (except for the case of iasiothiscallresolver.cpp). 00124 // We need to do this because IASIOThiscallResolver works by eclipsing the 00125 // original definition of ASIOInit() with a macro (see below). 00126 #if !defined(iasiothiscallresolver_sourcefile) 00127 #if !defined(__ASIO_H) 00128 #error iasiothiscallresolver.h must be included AFTER asio.h 00129 #endif 00130 #endif 00131 00132 #include <windows.h> 00133 #include <asiodrvr.h> /* From ASIO SDK */ 00134 00135 00136 class IASIOThiscallResolver : public IASIO { 00137 private: 00138 IASIO* that_; // Points to the real IASIO 00139 00140 static IASIOThiscallResolver instance; // Singleton instance 00141 00142 // Constructors - declared private so construction is limited to 00143 // our Singleton instance 00144 IASIOThiscallResolver(); 00145 IASIOThiscallResolver(IASIO* that); 00146 public: 00147 00148 // Methods from the IUnknown interface. We don't fully implement IUnknown 00149 // because the ASIO SDK never calls these methods through theAsioDriver ptr. 00150 // These methods are implemented as assert(false). 00151 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); 00152 virtual ULONG STDMETHODCALLTYPE AddRef(); 00153 virtual ULONG STDMETHODCALLTYPE Release(); 00154 00155 // Methods from the IASIO interface, implemented as forwarning calls to that. 00156 virtual ASIOBool init(void *sysHandle); 00157 virtual void getDriverName(char *name); 00158 virtual long getDriverVersion(); 00159 virtual void getErrorMessage(char *string); 00160 virtual ASIOError start(); 00161 virtual ASIOError stop(); 00162 virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); 00163 virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); 00164 virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); 00165 virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); 00166 virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); 00167 virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); 00168 virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); 00169 virtual ASIOError setClockSource(long reference); 00170 virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); 00171 virtual ASIOError getChannelInfo(ASIOChannelInfo *info); 00172 virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); 00173 virtual ASIOError disposeBuffers(); 00174 virtual ASIOError controlPanel(); 00175 virtual ASIOError future(long selector,void *opt); 00176 virtual ASIOError outputReady(); 00177 00178 // Class method, see ASIOInit() macro below. 00179 static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit 00180 }; 00181 00182 00183 // Replace calls to ASIOInit with our interposing version. 00184 // This macro enables us to perform thiscall resolution simply by #including 00185 // <iasiothiscallresolver.h> after the asio #includes (this file _must_ be 00186 // included _after_ the asio #includes) 00187 00188 #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) 00189 00190 00191 #endif /* !defined(_MSC_VER) */ 00192 00193 #endif /* Win32 */ 00194 00195 #endif /* included_iasiothiscallresolver_h */ 00196 00197