iasiothiscallresolver.h (9384B)
1 // **************************************************************************** 2 // File: IASIOThiscallResolver.h 3 // Description: The IASIOThiscallResolver class implements the IASIO 4 // interface and acts as a proxy to the real IASIO interface by 5 // calling through its vptr table using the thiscall calling 6 // convention. To put it another way, we interpose 7 // IASIOThiscallResolver between ASIO SDK code and the driver. 8 // This is necessary because most non-Microsoft compilers don't 9 // implement the thiscall calling convention used by IASIO. 10 // 11 // iasiothiscallresolver.cpp contains the background of this 12 // problem plus a technical description of the vptr 13 // manipulations. 14 // 15 // In order to use this mechanism one simply has to add 16 // iasiothiscallresolver.cpp to the list of files to compile 17 // and #include <iasiothiscallresolver.h> 18 // 19 // Note that this #include must come after the other ASIO SDK 20 // #includes, for example: 21 // 22 // #include <windows.h> 23 // #include <asiosys.h> 24 // #include <asio.h> 25 // #include <asiodrivers.h> 26 // #include <iasiothiscallresolver.h> 27 // 28 // Actually the important thing is to #include 29 // <iasiothiscallresolver.h> after <asio.h>. We have 30 // incorporated a test to enforce this ordering. 31 // 32 // The code transparently takes care of the interposition by 33 // using macro substitution to intercept calls to ASIOInit() 34 // and ASIOExit(). We save the original ASIO global 35 // "theAsioDriver" in our "that" variable, and then set 36 // "theAsioDriver" to equal our IASIOThiscallResolver instance. 37 // 38 // Whilst this method of resolving the thiscall problem requires 39 // the addition of #include <iasiothiscallresolver.h> to client 40 // code it has the advantage that it does not break the terms 41 // of the ASIO licence by publishing it. We are NOT modifying 42 // any Steinberg code here, we are merely implementing the IASIO 43 // interface in the same way that we would need to do if we 44 // wished to provide an open source ASIO driver. 45 // 46 // For compilation with MinGW -lole32 needs to be added to the 47 // linker options. For BORLAND, linking with Import32.lib is 48 // sufficient. 49 // 50 // The dependencies are with: CoInitialize, CoUninitialize, 51 // CoCreateInstance, CLSIDFromString - used by asiolist.cpp 52 // and are required on Windows whether ThiscallResolver is used 53 // or not. 54 // 55 // Searching for the above strings in the root library path 56 // of your compiler should enable the correct libraries to be 57 // identified if they aren't immediately obvious. 58 // 59 // Note that the current implementation of IASIOThiscallResolver 60 // is not COM compliant - it does not correctly implement the 61 // IUnknown interface. Implementing it is not necessary because 62 // it is not called by parts of the ASIO SDK which call through 63 // theAsioDriver ptr. The IUnknown methods are implemented as 64 // assert(false) to ensure that the code fails if they are 65 // ever called. 66 // Restrictions: None. Public Domain & Open Source distribute freely 67 // You may use IASIOThiscallResolver commercially as well as 68 // privately. 69 // You the user assume the responsibility for the use of the 70 // files, binary or text, and there is no guarantee or warranty, 71 // expressed or implied, including but not limited to the 72 // implied warranties of merchantability and fitness for a 73 // particular purpose. You assume all responsibility and agree 74 // to hold no entity, copyright holder or distributors liable 75 // for any loss of data or inaccurate representations of data 76 // as a result of using IASIOThiscallResolver. 77 // Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from 78 // Andrew Baldwin, and volatile for whole gcc asm blocks, 79 // both for compatibility with newer gcc versions. Cleaned up 80 // Borland asm to use one less register. 81 // 1.3 Switched to including assert.h for better compatibility. 82 // Wrapped entire .h and .cpp contents with a check for 83 // _MSC_VER to provide better compatibility with MS compilers. 84 // Changed Singleton implementation to use static instance 85 // instead of freestore allocated instance. Removed ASIOExit 86 // macro as it is no longer needed. 87 // 1.2 Removed semicolons from ASIOInit and ASIOExit macros to 88 // allow them to be embedded in expressions (if statements). 89 // Cleaned up some comments. Removed combase.c dependency (it 90 // doesn't compile with BCB anyway) by stubbing IUnknown. 91 // 1.1 Incorporated comments from Ross Bencina including things 92 // such as changing name from ThiscallResolver to 93 // IASIOThiscallResolver, tidying up the constructor, fixing 94 // a bug in IASIOThiscallResolver::ASIOExit() and improving 95 // portability through the use of conditional compilation 96 // 1.0 Initial working version. 97 // Created: 6/09/2003 98 // Authors: Fraser Adams 99 // Ross Bencina 100 // Rene G. Ceballos 101 // Martin Fay 102 // Antti Silvast 103 // Andrew Baldwin 104 // 105 // **************************************************************************** 106 107 108 #ifndef included_iasiothiscallresolver_h 109 #define included_iasiothiscallresolver_h 110 111 // We only need IASIOThiscallResolver at all if we are on Win32. For other 112 // platforms we simply bypass the IASIOThiscallResolver definition to allow us 113 // to be safely #include'd whatever the platform to keep client code portable 114 #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(_WIN64) 115 116 117 // If microsoft compiler we can call IASIO directly so IASIOThiscallResolver 118 // is not used. 119 #if !defined(_MSC_VER) 120 121 122 // The following is in order to ensure that this header is only included after 123 // the other ASIO headers (except for the case of iasiothiscallresolver.cpp). 124 // We need to do this because IASIOThiscallResolver works by eclipsing the 125 // original definition of ASIOInit() with a macro (see below). 126 #if !defined(iasiothiscallresolver_sourcefile) 127 #if !defined(__ASIO_H) 128 #error iasiothiscallresolver.h must be included AFTER asio.h 129 #endif 130 #endif 131 132 #include <windows.h> 133 #include <asiodrvr.h> /* From ASIO SDK */ 134 135 136 class IASIOThiscallResolver : public IASIO { 137 private: 138 IASIO* that_; // Points to the real IASIO 139 140 static IASIOThiscallResolver instance; // Singleton instance 141 142 // Constructors - declared private so construction is limited to 143 // our Singleton instance 144 IASIOThiscallResolver(); 145 IASIOThiscallResolver(IASIO* that); 146 public: 147 148 // Methods from the IUnknown interface. We don't fully implement IUnknown 149 // because the ASIO SDK never calls these methods through theAsioDriver ptr. 150 // These methods are implemented as assert(false). 151 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); 152 virtual ULONG STDMETHODCALLTYPE AddRef(); 153 virtual ULONG STDMETHODCALLTYPE Release(); 154 155 // Methods from the IASIO interface, implemented as forwarning calls to that. 156 virtual ASIOBool init(void *sysHandle); 157 virtual void getDriverName(char *name); 158 virtual long getDriverVersion(); 159 virtual void getErrorMessage(char *string); 160 virtual ASIOError start(); 161 virtual ASIOError stop(); 162 virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); 163 virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); 164 virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); 165 virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); 166 virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); 167 virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); 168 virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); 169 virtual ASIOError setClockSource(long reference); 170 virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); 171 virtual ASIOError getChannelInfo(ASIOChannelInfo *info); 172 virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); 173 virtual ASIOError disposeBuffers(); 174 virtual ASIOError controlPanel(); 175 virtual ASIOError future(long selector,void *opt); 176 virtual ASIOError outputReady(); 177 178 // Class method, see ASIOInit() macro below. 179 static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit 180 }; 181 182 183 // Replace calls to ASIOInit with our interposing version. 184 // This macro enables us to perform thiscall resolution simply by #including 185 // <iasiothiscallresolver.h> after the asio #includes (this file _must_ be 186 // included _after_ the asio #includes) 187 188 #define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) 189 190 191 #endif /* !defined(_MSC_VER) */ 192 193 #endif /* Win32 */ 194 195 #endif /* included_iasiothiscallresolver_h */ 196 197