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