1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2020 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11 Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12
13 End User License Agreement: www.juce.com/juce-6-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24 */
25
26 namespace juce
27 {
28
29 extern int64 getMouseEventTime();
30
31 JUCE_DECLARE_UUID_GETTER (IOleObject, "00000112-0000-0000-C000-000000000046")
32 JUCE_DECLARE_UUID_GETTER (IOleWindow, "00000114-0000-0000-C000-000000000046")
33 JUCE_DECLARE_UUID_GETTER (IOleInPlaceSite, "00000119-0000-0000-C000-000000000046")
34
35 namespace ActiveXHelpers
36 {
37 //==============================================================================
38 struct JuceIStorage : public ComBaseClassHelper<IStorage>
39 {
JuceIStoragejuce::ActiveXHelpers::JuceIStorage40 JuceIStorage() {}
41
CreateStreamjuce::ActiveXHelpers::JuceIStorage42 JUCE_COMRESULT CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
OpenStreamjuce::ActiveXHelpers::JuceIStorage43 JUCE_COMRESULT OpenStream (const WCHAR*, void*, DWORD, DWORD, IStream**) { return E_NOTIMPL; }
CreateStoragejuce::ActiveXHelpers::JuceIStorage44 JUCE_COMRESULT CreateStorage (const WCHAR*, DWORD, DWORD, DWORD, IStorage**) { return E_NOTIMPL; }
OpenStoragejuce::ActiveXHelpers::JuceIStorage45 JUCE_COMRESULT OpenStorage (const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage**) { return E_NOTIMPL; }
CopyTojuce::ActiveXHelpers::JuceIStorage46 JUCE_COMRESULT CopyTo (DWORD, IID const*, SNB, IStorage*) { return E_NOTIMPL; }
MoveElementTojuce::ActiveXHelpers::JuceIStorage47 JUCE_COMRESULT MoveElementTo (const OLECHAR*,IStorage*, const OLECHAR*, DWORD) { return E_NOTIMPL; }
Commitjuce::ActiveXHelpers::JuceIStorage48 JUCE_COMRESULT Commit (DWORD) { return E_NOTIMPL; }
Revertjuce::ActiveXHelpers::JuceIStorage49 JUCE_COMRESULT Revert() { return E_NOTIMPL; }
EnumElementsjuce::ActiveXHelpers::JuceIStorage50 JUCE_COMRESULT EnumElements (DWORD, void*, DWORD, IEnumSTATSTG**) { return E_NOTIMPL; }
DestroyElementjuce::ActiveXHelpers::JuceIStorage51 JUCE_COMRESULT DestroyElement (const OLECHAR*) { return E_NOTIMPL; }
RenameElementjuce::ActiveXHelpers::JuceIStorage52 JUCE_COMRESULT RenameElement (const WCHAR*, const WCHAR*) { return E_NOTIMPL; }
SetElementTimesjuce::ActiveXHelpers::JuceIStorage53 JUCE_COMRESULT SetElementTimes (const WCHAR*, FILETIME const*, FILETIME const*, FILETIME const*) { return E_NOTIMPL; }
SetClassjuce::ActiveXHelpers::JuceIStorage54 JUCE_COMRESULT SetClass (REFCLSID) { return S_OK; }
SetStateBitsjuce::ActiveXHelpers::JuceIStorage55 JUCE_COMRESULT SetStateBits (DWORD, DWORD) { return E_NOTIMPL; }
Statjuce::ActiveXHelpers::JuceIStorage56 JUCE_COMRESULT Stat (STATSTG*, DWORD) { return E_NOTIMPL; }
57 };
58
59 //==============================================================================
60 struct JuceOleInPlaceFrame : public ComBaseClassHelper<IOleInPlaceFrame>
61 {
JuceOleInPlaceFramejuce::ActiveXHelpers::JuceOleInPlaceFrame62 JuceOleInPlaceFrame (HWND hwnd) : window (hwnd) {}
63
GetWindowjuce::ActiveXHelpers::JuceOleInPlaceFrame64 JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
ContextSensitiveHelpjuce::ActiveXHelpers::JuceOleInPlaceFrame65 JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
GetBorderjuce::ActiveXHelpers::JuceOleInPlaceFrame66 JUCE_COMRESULT GetBorder (LPRECT) { return E_NOTIMPL; }
RequestBorderSpacejuce::ActiveXHelpers::JuceOleInPlaceFrame67 JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
SetBorderSpacejuce::ActiveXHelpers::JuceOleInPlaceFrame68 JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS) { return E_NOTIMPL; }
SetActiveObjectjuce::ActiveXHelpers::JuceOleInPlaceFrame69 JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR) { activeObject = a; return S_OK; }
InsertMenusjuce::ActiveXHelpers::JuceOleInPlaceFrame70 JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS) { return E_NOTIMPL; }
SetMenujuce::ActiveXHelpers::JuceOleInPlaceFrame71 JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND) { return S_OK; }
RemoveMenusjuce::ActiveXHelpers::JuceOleInPlaceFrame72 JUCE_COMRESULT RemoveMenus (HMENU) { return E_NOTIMPL; }
SetStatusTextjuce::ActiveXHelpers::JuceOleInPlaceFrame73 JUCE_COMRESULT SetStatusText (LPCOLESTR) { return S_OK; }
EnableModelessjuce::ActiveXHelpers::JuceOleInPlaceFrame74 JUCE_COMRESULT EnableModeless (BOOL) { return S_OK; }
TranslateAcceleratorjuce::ActiveXHelpers::JuceOleInPlaceFrame75 JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD) { return E_NOTIMPL; }
76
OfferKeyTranslationjuce::ActiveXHelpers::JuceOleInPlaceFrame77 HRESULT OfferKeyTranslation (LPMSG lpmsg)
78 {
79 if (activeObject != nullptr)
80 return activeObject->TranslateAcceleratorW (lpmsg);
81
82 return S_FALSE;
83 }
84
85 HWND window;
86 ComSmartPtr<IOleInPlaceActiveObject> activeObject;
87 };
88
89 //==============================================================================
90 struct JuceIOleInPlaceSite : public ComBaseClassHelper<IOleInPlaceSite>
91 {
JuceIOleInPlaceSitejuce::ActiveXHelpers::JuceIOleInPlaceSite92 JuceIOleInPlaceSite (HWND hwnd)
93 : window (hwnd),
94 frame (new JuceOleInPlaceFrame (window))
95 {}
96
~JuceIOleInPlaceSitejuce::ActiveXHelpers::JuceIOleInPlaceSite97 ~JuceIOleInPlaceSite()
98 {
99 frame->Release();
100 }
101
GetWindowjuce::ActiveXHelpers::JuceIOleInPlaceSite102 JUCE_COMRESULT GetWindow (HWND* lphwnd) { *lphwnd = window; return S_OK; }
ContextSensitiveHelpjuce::ActiveXHelpers::JuceIOleInPlaceSite103 JUCE_COMRESULT ContextSensitiveHelp (BOOL) { return E_NOTIMPL; }
CanInPlaceActivatejuce::ActiveXHelpers::JuceIOleInPlaceSite104 JUCE_COMRESULT CanInPlaceActivate() { return S_OK; }
OnInPlaceActivatejuce::ActiveXHelpers::JuceIOleInPlaceSite105 JUCE_COMRESULT OnInPlaceActivate() { return S_OK; }
OnUIActivatejuce::ActiveXHelpers::JuceIOleInPlaceSite106 JUCE_COMRESULT OnUIActivate() { return S_OK; }
107
GetWindowContextjuce::ActiveXHelpers::JuceIOleInPlaceSite108 JUCE_COMRESULT GetWindowContext (LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO lpFrameInfo)
109 {
110 /* Note: If you call AddRef on the frame here, then some types of object (e.g. web browser control) cause leaks..
111 If you don't call AddRef then others crash (e.g. QuickTime).. Bit of a catch-22, so letting it leak is probably preferable.
112 */
113 if (lplpFrame != nullptr) { frame->AddRef(); *lplpFrame = frame; }
114 if (lplpDoc != nullptr) *lplpDoc = nullptr;
115 lpFrameInfo->fMDIApp = FALSE;
116 lpFrameInfo->hwndFrame = window;
117 lpFrameInfo->haccel = nullptr;
118 lpFrameInfo->cAccelEntries = 0;
119 return S_OK;
120 }
121
Scrolljuce::ActiveXHelpers::JuceIOleInPlaceSite122 JUCE_COMRESULT Scroll (SIZE) { return E_NOTIMPL; }
OnUIDeactivatejuce::ActiveXHelpers::JuceIOleInPlaceSite123 JUCE_COMRESULT OnUIDeactivate (BOOL) { return S_OK; }
OnInPlaceDeactivatejuce::ActiveXHelpers::JuceIOleInPlaceSite124 JUCE_COMRESULT OnInPlaceDeactivate() { return S_OK; }
DiscardUndoStatejuce::ActiveXHelpers::JuceIOleInPlaceSite125 JUCE_COMRESULT DiscardUndoState() { return E_NOTIMPL; }
DeactivateAndUndojuce::ActiveXHelpers::JuceIOleInPlaceSite126 JUCE_COMRESULT DeactivateAndUndo() { return E_NOTIMPL; }
OnPosRectChangejuce::ActiveXHelpers::JuceIOleInPlaceSite127 JUCE_COMRESULT OnPosRectChange (LPCRECT) { return S_OK; }
128
offerEventToActiveXControljuce::ActiveXHelpers::JuceIOleInPlaceSite129 LRESULT offerEventToActiveXControl (::MSG& msg)
130 {
131 if (frame != nullptr)
132 return frame->OfferKeyTranslation (&msg);
133
134 return S_FALSE;
135 }
136
137 HWND window;
138 JuceOleInPlaceFrame* frame;
139 };
140
141 //==============================================================================
142 struct JuceIOleClientSite : public ComBaseClassHelper<IOleClientSite>
143 {
JuceIOleClientSitejuce::ActiveXHelpers::JuceIOleClientSite144 JuceIOleClientSite (HWND window) : inplaceSite (new JuceIOleInPlaceSite (window))
145 {}
146
~JuceIOleClientSitejuce::ActiveXHelpers::JuceIOleClientSite147 ~JuceIOleClientSite()
148 {
149 inplaceSite->Release();
150 }
151
QueryInterfacejuce::ActiveXHelpers::JuceIOleClientSite152 JUCE_COMRESULT QueryInterface (REFIID type, void** result)
153 {
154 if (type == __uuidof (IOleInPlaceSite))
155 {
156 inplaceSite->AddRef();
157 *result = static_cast<IOleInPlaceSite*> (inplaceSite);
158 return S_OK;
159 }
160
161 return ComBaseClassHelper <IOleClientSite>::QueryInterface (type, result);
162 }
163
SaveObjectjuce::ActiveXHelpers::JuceIOleClientSite164 JUCE_COMRESULT SaveObject() { return E_NOTIMPL; }
GetMonikerjuce::ActiveXHelpers::JuceIOleClientSite165 JUCE_COMRESULT GetMoniker (DWORD, DWORD, IMoniker**) { return E_NOTIMPL; }
GetContainerjuce::ActiveXHelpers::JuceIOleClientSite166 JUCE_COMRESULT GetContainer (LPOLECONTAINER* ppContainer) { *ppContainer = nullptr; return E_NOINTERFACE; }
ShowObjectjuce::ActiveXHelpers::JuceIOleClientSite167 JUCE_COMRESULT ShowObject() { return S_OK; }
OnShowWindowjuce::ActiveXHelpers::JuceIOleClientSite168 JUCE_COMRESULT OnShowWindow (BOOL) { return E_NOTIMPL; }
RequestNewObjectLayoutjuce::ActiveXHelpers::JuceIOleClientSite169 JUCE_COMRESULT RequestNewObjectLayout() { return E_NOTIMPL; }
170
offerEventToActiveXControljuce::ActiveXHelpers::JuceIOleClientSite171 LRESULT offerEventToActiveXControl (::MSG& msg)
172 {
173 if (inplaceSite != nullptr)
174 return inplaceSite->offerEventToActiveXControl (msg);
175
176 return S_FALSE;
177 }
178
179 JuceIOleInPlaceSite* inplaceSite;
180 };
181
182 //==============================================================================
183 static Array<ActiveXControlComponent*> activeXComps;
184
getHWND(const ActiveXControlComponent * const component)185 static HWND getHWND (const ActiveXControlComponent* const component)
186 {
187 HWND hwnd = {};
188 const IID iid = __uuidof (IOleWindow);
189
190 if (auto* window = (IOleWindow*) component->queryInterface (&iid))
191 {
192 window->GetWindow (&hwnd);
193 window->Release();
194 }
195
196 return hwnd;
197 }
198
offerActiveXMouseEventToPeer(ComponentPeer * peer,HWND hwnd,UINT message,LPARAM lParam)199 static void offerActiveXMouseEventToPeer (ComponentPeer* peer, HWND hwnd, UINT message, LPARAM lParam)
200 {
201 switch (message)
202 {
203 case WM_MOUSEMOVE:
204 case WM_LBUTTONDOWN:
205 case WM_MBUTTONDOWN:
206 case WM_RBUTTONDOWN:
207 case WM_LBUTTONUP:
208 case WM_MBUTTONUP:
209 case WM_RBUTTONUP:
210 {
211 RECT activeXRect, peerRect;
212 GetWindowRect (hwnd, &activeXRect);
213 GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
214
215 peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse,
216 { (float) (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left),
217 (float) (GET_Y_LPARAM (lParam) + activeXRect.top - peerRect.top) },
218 ComponentPeer::getCurrentModifiersRealtime(),
219 MouseInputSource::invalidPressure,
220 MouseInputSource::invalidOrientation,
221 getMouseEventTime());
222 break;
223 }
224
225 default:
226 break;
227 }
228 }
229 }
230
231 //==============================================================================
232 class ActiveXControlComponent::Pimpl : public ComponentMovementWatcher
233 #if JUCE_WIN_PER_MONITOR_DPI_AWARE
234 , public ComponentPeer::ScaleFactorListener
235 #endif
236 {
237 public:
Pimpl(HWND hwnd,ActiveXControlComponent & activeXComp)238 Pimpl (HWND hwnd, ActiveXControlComponent& activeXComp)
239 : ComponentMovementWatcher (&activeXComp),
240 owner (activeXComp),
241 storage (new ActiveXHelpers::JuceIStorage()),
242 clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd))
243 {
244 }
245
~Pimpl()246 ~Pimpl()
247 {
248 if (control != nullptr)
249 {
250 control->Close (OLECLOSE_NOSAVE);
251 control->Release();
252 }
253
254 clientSite->Release();
255 storage->Release();
256
257 #if JUCE_WIN_PER_MONITOR_DPI_AWARE
258 for (int i = 0; i < ComponentPeer::getNumPeers(); ++i)
259 if (auto* peer = ComponentPeer::getPeer (i))
260 peer->removeScaleFactorListener (this);
261 #endif
262 }
263
setControlBounds(Rectangle<int> newBounds) const264 void setControlBounds (Rectangle<int> newBounds) const
265 {
266 if (controlHWND != nullptr)
267 {
268 #if JUCE_WIN_PER_MONITOR_DPI_AWARE
269 if (auto* peer = owner.getTopLevelComponent()->getPeer())
270 newBounds = (newBounds.toDouble() * peer->getPlatformScaleFactor()).toNearestInt();
271 #endif
272
273 MoveWindow (controlHWND, newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight(), TRUE);
274 }
275
276 }
277
setControlVisible(bool shouldBeVisible) const278 void setControlVisible (bool shouldBeVisible) const
279 {
280 if (controlHWND != nullptr)
281 ShowWindow (controlHWND, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
282 }
283
284 //==============================================================================
285 using ComponentMovementWatcher::componentMovedOrResized;
286
componentMovedOrResized(bool,bool)287 void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
288 {
289 if (auto* peer = owner.getTopLevelComponent()->getPeer())
290 setControlBounds (peer->getAreaCoveredBy (owner));
291 }
292
componentPeerChanged()293 void componentPeerChanged() override
294 {
295 componentMovedOrResized (true, true);
296
297 #if JUCE_WIN_PER_MONITOR_DPI_AWARE
298 if (auto* peer = owner.getTopLevelComponent()->getPeer())
299 peer->addScaleFactorListener (this);
300 #endif
301 }
302
303 using ComponentMovementWatcher::componentVisibilityChanged;
304
componentVisibilityChanged()305 void componentVisibilityChanged() override
306 {
307 setControlVisible (owner.isShowing());
308 componentPeerChanged();
309 }
310
311 #if JUCE_WIN_PER_MONITOR_DPI_AWARE
nativeScaleFactorChanged(double)312 void nativeScaleFactorChanged (double /*newScaleFactor*/) override
313 {
314 componentMovedOrResized (true, true);
315 }
316 #endif
317
318 // intercepts events going to an activeX control, so we can sneakily use the mouse events
activeXHookWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)319 static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
320 {
321 for (auto* ax : ActiveXHelpers::activeXComps)
322 {
323 if (ax->control != nullptr && ax->control->controlHWND == hwnd)
324 {
325 switch (message)
326 {
327 case WM_MOUSEMOVE:
328 case WM_LBUTTONDOWN:
329 case WM_MBUTTONDOWN:
330 case WM_RBUTTONDOWN:
331 case WM_LBUTTONUP:
332 case WM_MBUTTONUP:
333 case WM_RBUTTONUP:
334 case WM_LBUTTONDBLCLK:
335 case WM_MBUTTONDBLCLK:
336 case WM_RBUTTONDBLCLK:
337 if (ax->isShowing())
338 {
339 if (auto* peer = ax->getPeer())
340 {
341 ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
342
343 if (! ax->areMouseEventsAllowed())
344 return 0;
345 }
346 }
347 break;
348
349 default:
350 break;
351 }
352
353 return CallWindowProc (ax->control->originalWndProc, hwnd, message, wParam, lParam);
354 }
355 }
356
357 return DefWindowProc (hwnd, message, wParam, lParam);
358 }
359
360 ActiveXControlComponent& owner;
361 HWND controlHWND = {};
362 IStorage* storage = nullptr;
363 ActiveXHelpers::JuceIOleClientSite* clientSite = nullptr;
364 IOleObject* control = nullptr;
365 WNDPROC originalWndProc = nullptr;
366 };
367
368 //==============================================================================
ActiveXControlComponent()369 ActiveXControlComponent::ActiveXControlComponent()
370 {
371 ActiveXHelpers::activeXComps.add (this);
372 }
373
~ActiveXControlComponent()374 ActiveXControlComponent::~ActiveXControlComponent()
375 {
376 deleteControl();
377 ActiveXHelpers::activeXComps.removeFirstMatchingValue (this);
378 }
379
paint(Graphics & g)380 void ActiveXControlComponent::paint (Graphics& g)
381 {
382 if (control == nullptr)
383 g.fillAll (Colours::lightgrey);
384 }
385
createControl(const void * controlIID)386 bool ActiveXControlComponent::createControl (const void* controlIID)
387 {
388 deleteControl();
389
390 if (auto* peer = getPeer())
391 {
392 auto controlBounds = peer->getAreaCoveredBy (*this);
393 auto hwnd = (HWND) peer->getNativeHandle();
394
395 std::unique_ptr<Pimpl> newControl (new Pimpl (hwnd, *this));
396
397 HRESULT hr = OleCreate (*(const IID*) controlIID, __uuidof (IOleObject), 1 /*OLERENDER_DRAW*/, nullptr,
398 newControl->clientSite, newControl->storage,
399 (void**) &(newControl->control));
400
401 if (hr == S_OK)
402 {
403 newControl->control->SetHostNames (L"JUCE", nullptr);
404
405 if (OleSetContainedObject (newControl->control, TRUE) == S_OK)
406 {
407 RECT rect;
408 rect.left = controlBounds.getX();
409 rect.top = controlBounds.getY();
410 rect.right = controlBounds.getRight();
411 rect.bottom = controlBounds.getBottom();
412
413 if (newControl->control->DoVerb (OLEIVERB_SHOW, nullptr, newControl->clientSite, 0, hwnd, &rect) == S_OK)
414 {
415 control.reset (newControl.release());
416 control->controlHWND = ActiveXHelpers::getHWND (this);
417
418 if (control->controlHWND != nullptr)
419 {
420 control->setControlBounds (controlBounds);
421
422 control->originalWndProc = (WNDPROC) GetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC);
423 SetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC, (LONG_PTR) Pimpl::activeXHookWndProc);
424 }
425
426 return true;
427 }
428 }
429 }
430 }
431 else
432 {
433 // the component must have already been added to a real window when you call this!
434 jassertfalse;
435 }
436
437 return false;
438 }
439
deleteControl()440 void ActiveXControlComponent::deleteControl()
441 {
442 control = nullptr;
443 }
444
queryInterface(const void * iid) const445 void* ActiveXControlComponent::queryInterface (const void* iid) const
446 {
447 void* result = nullptr;
448
449 if (control != nullptr && control->control != nullptr
450 && SUCCEEDED (control->control->QueryInterface (*(const IID*) iid, &result)))
451 return result;
452
453 return nullptr;
454 }
455
setMouseEventsAllowed(const bool eventsCanReachControl)456 void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachControl)
457 {
458 mouseEventsAllowed = eventsCanReachControl;
459 }
460
offerEventToActiveXControl(void * ptr)461 intptr_t ActiveXControlComponent::offerEventToActiveXControl (void* ptr)
462 {
463 if (control != nullptr && control->clientSite != nullptr)
464 return (intptr_t) control->clientSite->offerEventToActiveXControl (*reinterpret_cast<::MSG*> (ptr));
465
466 return S_FALSE;
467 }
468
offerEventToActiveXControlStatic(void * ptr)469 intptr_t ActiveXControlComponent::offerEventToActiveXControlStatic (void* ptr)
470 {
471 for (auto* ax : ActiveXHelpers::activeXComps)
472 {
473 auto result = ax->offerEventToActiveXControl (ptr);
474
475 if (result != S_FALSE)
476 return result;
477 }
478
479 return S_FALSE;
480 }
481
juce_offerEventToActiveXControl(::MSG & msg)482 LRESULT juce_offerEventToActiveXControl (::MSG& msg)
483 {
484 if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
485 return ActiveXControlComponent::offerEventToActiveXControlStatic (&msg);
486
487 return S_FALSE;
488 }
489
490 } // namespace juce
491