]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/automtn.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/ole/automtn.cpp 
   3 // Purpose:     OLE automation utilities 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) 1998, Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  15 #if defined(__BORLANDC__) 
  21 // Watcom C++ gives a linker error if this is compiled in. 
  22 // With Borland C++, all samples crash if this is compiled in. 
  23 #if wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__) 
  25 #define _FORCENAMELESSUNION 
  27 #include "wx/msw/private.h" 
  28 #include "wx/msw/ole/oleutils.h" 
  29 #include "wx/msw/ole/automtn.h" 
  33 #include "wx/msw/wince/time.h" 
  51 #include "wx/datetime.h" 
  52 #endif // wxUSE_TIMEDATE 
  54 static void ClearVariant(VARIANTARG 
*pvarg
) ; 
  55 static void ReleaseVariant(VARIANTARG 
*pvarg
) ; 
  56 // static void ShowException(LPOLESTR szMember, HRESULT hr, EXCEPINFO *pexcep, unsigned int uiArgErr); 
  62 wxAutomationObject::wxAutomationObject(WXIDISPATCH
* dispatchPtr
) 
  64     m_dispatchPtr 
= dispatchPtr
; 
  67 wxAutomationObject::~wxAutomationObject() 
  71         ((IDispatch
*)m_dispatchPtr
)->Release(); 
  76 #define INVOKEARG(i) (args ? args[i] : *(ptrArgs[i])) 
  78 // For Put/Get, no named arguments are allowed. 
  79 bool wxAutomationObject::Invoke(const wxString
& member
, int action
, 
  80         wxVariant
& retValue
, int noArgs
, wxVariant args
[], const wxVariant
* ptrArgs
[]) const 
  85     // nonConstMember is necessary because the wxString class doesn't have enough consts... 
  86     wxString 
nonConstMember(member
); 
  88     int ch 
= nonConstMember
.Find('.'); 
  91         // Use dot notation to get the next object 
  92         wxString 
member2(nonConstMember
.Left((size_t) ch
)); 
  93         wxString 
rest(nonConstMember
.Right(nonConstMember
.Length() - ch 
- 1)); 
  94         wxAutomationObject obj
; 
  95         if (!GetObject(obj
, member2
)) 
  97         return obj
.Invoke(rest
, action
, retValue
, noArgs
, args
, ptrArgs
); 
 101     ClearVariant(& vReturn
); 
 103     VARIANTARG
* vReturnPtr 
= & vReturn
; 
 105     // Find number of names args 
 106     int namedArgCount 
= 0; 
 108     for (i 
= 0; i 
< noArgs
; i
++) 
 109         if (!INVOKEARG(i
).GetName().IsNull()) 
 114     int namedArgStringCount 
= namedArgCount 
+ 1; 
 115     BSTR
* argNames 
= new BSTR
[namedArgStringCount
]; 
 116     argNames
[0] = wxConvertStringToOle(member
); 
 118     // Note that arguments are specified in reverse order 
 119     // (all totally logical; hey, we're dealing with OLE here.) 
 122     for (i 
= 0; i 
< namedArgCount
; i
++) 
 124         if (!INVOKEARG(i
).GetName().IsNull()) 
 126             argNames
[(namedArgCount
-j
)] = wxConvertStringToOle(INVOKEARG(i
).GetName()); 
 131     // + 1 for the member name, + 1 again in case we're a 'put' 
 132     DISPID
* dispIds 
= new DISPID
[namedArgCount 
+ 2]; 
 135     DISPPARAMS dispparams
; 
 136     unsigned int uiArgErr
; 
 139     // Get the IDs for the member and its arguments.  GetIDsOfNames expects the 
 140     // member name as the first name, followed by argument names (if any). 
 141     hr 
= ((IDispatch
*)m_dispatchPtr
)->GetIDsOfNames(IID_NULL
, argNames
, 
 142                                 1 + namedArgCount
, LOCALE_SYSTEM_DEFAULT
, dispIds
); 
 145 //        ShowException(szMember, hr, NULL, 0); 
 151     // if doing a property put(ref), we need to adjust the first argument to have a 
 152     // named arg of DISPID_PROPERTYPUT. 
 153     if (action 
& (DISPATCH_PROPERTYPUT 
| DISPATCH_PROPERTYPUTREF
)) 
 156         dispIds
[1] = DISPID_PROPERTYPUT
; 
 157         vReturnPtr 
= (VARIANTARG
*) NULL
; 
 160     // Convert the wxVariants to VARIANTARGs 
 161     VARIANTARG
* oleArgs 
= new VARIANTARG
[noArgs
]; 
 162     for (i 
= 0; i 
< noArgs
; i
++) 
 164         // Again, reverse args 
 165         if (!wxConvertVariantToOle(INVOKEARG((noArgs
-1) - i
), oleArgs
[i
])) 
 174     dispparams
.rgdispidNamedArgs 
= dispIds 
+ 1; 
 175     dispparams
.rgvarg 
= oleArgs
; 
 176     dispparams
.cArgs 
= noArgs
; 
 177     dispparams
.cNamedArgs 
= namedArgCount
; 
 179     excep
.pfnDeferredFillIn 
= NULL
; 
 181     hr 
= ((IDispatch
*)m_dispatchPtr
)->Invoke(dispIds
[0], IID_NULL
, LOCALE_SYSTEM_DEFAULT
, 
 182                         (WORD
)action
, &dispparams
, vReturnPtr
, &excep
, &uiArgErr
); 
 184     for (i 
= 0; i 
< namedArgStringCount
; i
++) 
 186         SysFreeString(argNames
[i
]); 
 191     for (i 
= 0; i 
< noArgs
; i
++) 
 192         ReleaseVariant(& oleArgs
[i
]) ; 
 197         // display the exception information if appropriate: 
 198 //        ShowException((const char*) member, hr, &excep, uiArgErr); 
 200         // free exception structure information 
 201         SysFreeString(excep
.bstrSource
); 
 202         SysFreeString(excep
.bstrDescription
); 
 203         SysFreeString(excep
.bstrHelpFile
); 
 206             ReleaseVariant(vReturnPtr
); 
 213             // Convert result to wxVariant form 
 214             wxConvertOleToVariant(vReturn
, retValue
); 
 215             // Mustn't release the dispatch pointer 
 216             if (vReturn
.vt 
== VT_DISPATCH
) 
 218                 vReturn
.pdispVal 
= (IDispatch
*) NULL
; 
 220             ReleaseVariant(& vReturn
); 
 226 // Invoke a member function 
 227 wxVariant 
wxAutomationObject::CallMethod(const wxString
& member
, int noArgs
, wxVariant args
[]) 
 229     wxVariant retVariant
; 
 230     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, args
)) 
 232         retVariant
.MakeNull(); 
 237 wxVariant 
wxAutomationObject::CallMethodArray(const wxString
& member
, int noArgs
, const wxVariant 
**args
) 
 239     wxVariant retVariant
; 
 240     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, noArgs
, NULL
, args
)) 
 242         retVariant
.MakeNull(); 
 247 wxVariant 
wxAutomationObject::CallMethod(const wxString
& member
, 
 248         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 249         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 250         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 252     const wxVariant
** args 
= new const wxVariant
*[6]; 
 284     wxVariant retVariant
; 
 285     if (!Invoke(member
, DISPATCH_METHOD
, retVariant
, i
, NULL
, args
)) 
 287         retVariant
.MakeNull(); 
 294 wxVariant 
wxAutomationObject::GetPropertyArray(const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 296     wxVariant retVariant
; 
 297     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
)) 
 299         retVariant
.MakeNull(); 
 303 wxVariant 
wxAutomationObject::GetProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 305     wxVariant retVariant
; 
 306     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
)) 
 308         retVariant
.MakeNull(); 
 313 wxVariant 
wxAutomationObject::GetProperty(const wxString
& property
, 
 314         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 315         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 316         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 318     const wxVariant
** args 
= new const wxVariant
*[6]; 
 350     wxVariant retVariant
; 
 351     if (!Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, i
, NULL
, args
)) 
 353         retVariant
.MakeNull(); 
 359 bool wxAutomationObject::PutProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) 
 361     wxVariant retVariant
; 
 362     if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, args
)) 
 369 bool wxAutomationObject::PutPropertyArray(const wxString
& property
, int noArgs
, const wxVariant 
**args
) 
 371     wxVariant retVariant
; 
 372     if (!Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, noArgs
, NULL
, args
)) 
 379 bool wxAutomationObject::PutProperty(const wxString
& property
, 
 380         const wxVariant
& arg1
, const wxVariant
& arg2
, 
 381         const wxVariant
& arg3
, const wxVariant
& arg4
, 
 382         const wxVariant
& arg5
, const wxVariant
& arg6
) 
 384     const wxVariant
** args 
= new const wxVariant
*[6]; 
 416     wxVariant retVariant
; 
 417     bool ret 
= Invoke(property
, DISPATCH_PROPERTYPUT
, retVariant
, i
, NULL
, args
); 
 423 // Uses DISPATCH_PROPERTYGET 
 424 // and returns a dispatch pointer. The calling code should call Release 
 425 // on the pointer, though this could be implicit by constructing an wxAutomationObject 
 426 // with it and letting the destructor call Release. 
 427 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 429     wxVariant retVariant
; 
 430     if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, args
)) 
 432         if (retVariant
.GetType() == wxT("void*")) 
 434             return (WXIDISPATCH
*) retVariant
.GetVoidPtr(); 
 438     return (WXIDISPATCH
*) NULL
; 
 441 // Uses DISPATCH_PROPERTYGET 
 442 // and returns a dispatch pointer. The calling code should call Release 
 443 // on the pointer, though this could be implicit by constructing an wxAutomationObject 
 444 // with it and letting the destructor call Release. 
 445 WXIDISPATCH
* wxAutomationObject::GetDispatchProperty(const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 447     wxVariant retVariant
; 
 448     if (Invoke(property
, DISPATCH_PROPERTYGET
, retVariant
, noArgs
, NULL
, args
)) 
 450         if (retVariant
.GetType() == wxT("void*")) 
 452             return (WXIDISPATCH
*) retVariant
.GetVoidPtr(); 
 456     return (WXIDISPATCH
*) NULL
; 
 460 // A way of initialising another wxAutomationObject with a dispatch object 
 461 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, wxVariant args
[]) const 
 463     WXIDISPATCH
* dispatch 
= GetDispatchProperty(property
, noArgs
, args
); 
 466         obj
.SetDispatchPtr(dispatch
); 
 473 // A way of initialising another wxAutomationObject with a dispatch object 
 474 bool wxAutomationObject::GetObject(wxAutomationObject
& obj
, const wxString
& property
, int noArgs
, const wxVariant 
**args
) const 
 476     WXIDISPATCH
* dispatch 
= GetDispatchProperty(property
, noArgs
, args
); 
 479         obj
.SetDispatchPtr(dispatch
); 
 486 // Get a dispatch pointer from the current object associated 
 488 bool wxAutomationObject::GetInstance(const wxString
& classId
) const 
 494     IUnknown 
* pUnk 
= NULL
; 
 496     wxBasicString 
unicodeName(classId
.mb_str()); 
 498     if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
))) 
 500         wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); 
 504     if (FAILED(GetActiveObject(clsId
, NULL
, &pUnk
))) 
 506         wxLogWarning(wxT("Cannot find an active object")); 
 510     if (pUnk
->QueryInterface(IID_IDispatch
, (LPVOID
*) &m_dispatchPtr
) != S_OK
) 
 512         wxLogWarning(wxT("Cannot find IDispatch interface")); 
 519 // Get a dispatch pointer from a new object associated 
 520 // with the given class id 
 521 bool wxAutomationObject::CreateInstance(const wxString
& classId
) const 
 528     wxBasicString 
unicodeName(classId
.mb_str()); 
 530     if (FAILED(CLSIDFromProgID((BSTR
) unicodeName
, &clsId
))) 
 532         wxLogWarning(wxT("Cannot obtain CLSID from ProgID")); 
 536     // start a new copy of Excel, grab the IDispatch interface 
 537     if (FAILED(CoCreateInstance(clsId
, NULL
, CLSCTX_LOCAL_SERVER
, IID_IDispatch
, (void**)&m_dispatchPtr
))) 
 539         wxLogWarning(wxT("Cannot start an instance of this class.")); 
 547 WXDLLEXPORT 
bool wxConvertVariantToOle(const wxVariant
& variant
, VARIANTARG
& oleVariant
) 
 549     ClearVariant(&oleVariant
); 
 550     if (variant
.IsNull()) 
 552         oleVariant
.vt 
= VT_NULL
; 
 556     wxString 
type(variant
.GetType()); 
 559     if (type 
== wxT("long")) 
 561         oleVariant
.vt 
= VT_I4
; 
 562         oleVariant
.lVal 
= variant
.GetLong() ; 
 564     // cVal not always present 
 566     else if (type 
== wxT("char")) 
 568         oleVariant
.vt
=VT_I1
;            // Signed Char 
 569         oleVariant
.cVal
=variant
.GetChar(); 
 572     else if (type 
== wxT("double")) 
 574         oleVariant
.vt 
= VT_R8
; 
 575         oleVariant
.dblVal 
= variant
.GetDouble(); 
 577     else if (type 
== wxT("bool")) 
 579         oleVariant
.vt 
= VT_BOOL
; 
 580         // 'bool' required for VC++ 4 apparently 
 581 #if (defined(__VISUALC__) && (__VISUALC__ <= 1000)) 
 582         oleVariant
.bool = variant
.GetBool(); 
 584         oleVariant
.boolVal 
= variant
.GetBool(); 
 587     else if (type 
== wxT("string")) 
 589         wxString 
str( variant
.GetString() ); 
 590         oleVariant
.vt 
= VT_BSTR
; 
 591         oleVariant
.bstrVal 
= wxConvertStringToOle(str
); 
 594     else if (type 
== wxT("datetime")) 
 596         wxDateTime 
date( variant
.GetDateTime() ); 
 597         oleVariant
.vt 
= VT_DATE
; 
 599         long dosDateTime 
= date
.GetAsDOS(); 
 600         short dosDate 
= short((dosDateTime 
& 0xFFFF0000) >> 16); 
 601         short dosTime 
= short(dosDateTime 
& 0xFFFF); 
 603         DosDateTimeToVariantTime(dosDate
, dosTime
, & oleVariant
.date
); 
 606     else if (type 
== wxT("void*")) 
 608         oleVariant
.vt 
= VT_DISPATCH
; 
 609         oleVariant
.pdispVal 
= (IDispatch
*) variant
.GetVoidPtr(); 
 611     else if (type 
== wxT("list") || type 
== wxT("stringlist")) 
 613         oleVariant
.vt 
= VT_VARIANT 
| VT_ARRAY
; 
 616         SAFEARRAYBOUND saBound
; 
 617         VARIANTARG 
*pvargBase
; 
 621         int iCount 
= variant
.GetCount(); 
 624         saBound
.cElements 
= iCount
; 
 626         psa 
= SafeArrayCreate(VT_VARIANT
, 1, &saBound
); 
 630         SafeArrayAccessData(psa
, (void**)&pvargBase
); 
 633         for (i 
= 0; i 
< iCount
; i
++) 
 635             // copy each string in the list of strings 
 636             wxVariant 
eachVariant(variant
[i
]); 
 637             if (!wxConvertVariantToOle(eachVariant
, * pvarg
)) 
 639                 // memory failure:  back out and free strings alloc'ed up to 
 640                 // now, and then the array itself. 
 642                 for (j 
= 0; j 
< i
; j
++) 
 644                     SysFreeString(pvarg
->bstrVal
); 
 647                 SafeArrayDestroy(psa
); 
 653         SafeArrayUnaccessData(psa
); 
 655         oleVariant
.parray 
= psa
; 
 659         oleVariant
.vt 
= VT_NULL
; 
 666 #define VT_TYPEMASK 0xfff 
 669 WXDLLEXPORT 
bool wxConvertOleToVariant(const VARIANTARG
& oleVariant
, wxVariant
& variant
) 
 671     switch (oleVariant
.vt 
& VT_TYPEMASK
) 
 675             wxString 
str(wxConvertStringFromOle(oleVariant
.bstrVal
)); 
 682             unsigned short dosDate 
= 0; 
 683             unsigned short dosTime 
= 0; 
 684             VariantTimeToDosDateTime(oleVariant
.date
, & dosDate
, & dosTime
); 
 686             long dosDateTime 
= (dosDate 
<< 16) || dosTime
; 
 688             date
.SetFromDOS(dosDateTime
); 
 695             variant 
= (long) oleVariant
.lVal
; 
 700             variant 
= (long) oleVariant
.iVal
; 
 706 #if (defined(_MSC_VER) && (_MSC_VER <= 1000) && !defined(__MWERKS__) ) //GC 
 707 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type 
 708             variant 
= (long) (oleVariant
.bool != 0); 
 710             variant 
= (bool) (oleVariant
.bool != 0); 
 713 #ifndef HAVE_BOOL // Can't use bool operator if no native bool type 
 714             variant 
= (long) (oleVariant
.boolVal 
!= 0); 
 716             variant 
= (bool) (oleVariant
.boolVal 
!= 0); 
 723             variant 
= oleVariant
.dblVal
; 
 730             int cDims
, cElements
, i
; 
 733             // Iterate the dimensions: number of elements is x*y*z 
 734             for (cDims 
= 0, cElements 
= 1; 
 735                 cDims 
< oleVariant
.parray
->cDims
; cDims 
++) 
 736                     cElements 
*= oleVariant
.parray
->rgsabound
[cDims
].cElements
; 
 738             // Get a pointer to the data 
 739             HRESULT hr 
= SafeArrayAccessData(oleVariant
.parray
, (void HUGEP
* FAR
*) & pvdata
); 
 743             for (i 
= 0; i 
< cElements
; i
++) 
 745                 VARIANTARG
& oleElement 
= pvdata
[i
]; 
 747                 if (!wxConvertOleToVariant(oleElement
, vElement
)) 
 750                 variant
.Append(vElement
); 
 752             SafeArrayUnaccessData(oleVariant
.parray
); 
 757             variant 
= (void*) oleVariant
.pdispVal
; 
 767             break;    // Ignore Empty Variant, used only during destruction of objects 
 771             wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type")); 
 781  *  Zeros a variant structure without regard to current contents 
 783 static void ClearVariant(VARIANTARG 
*pvarg
) 
 785     pvarg
->vt 
= VT_EMPTY
; 
 786     pvarg
->wReserved1 
= 0; 
 787     pvarg
->wReserved2 
= 0; 
 788     pvarg
->wReserved3 
= 0; 
 795  *  Clears a particular variant structure and releases any external objects 
 796  *  or memory contained in the variant.  Supports the data types listed above. 
 798 static void ReleaseVariant(VARIANTARG 
*pvarg
) 
 801     VARIANTARG _huge 
*pvargArray
; 
 802     long lLBound
, lUBound
, l
; 
 804     vt 
= (VARTYPE
)(pvarg
->vt 
& 0xfff);        // mask off flags 
 806     // check if an array.  If so, free its contents, then the array itself. 
 807     if (V_ISARRAY(pvarg
)) 
 809         // variant arrays are all this routine currently knows about.  Since a 
 810         // variant can contain anything (even other arrays), call ourselves 
 812         if (vt 
== VT_VARIANT
) 
 814             SafeArrayGetLBound(pvarg
->parray
, 1, &lLBound
); 
 815             SafeArrayGetUBound(pvarg
->parray
, 1, &lUBound
); 
 817             if (lUBound 
> lLBound
) 
 821                 SafeArrayAccessData(pvarg
->parray
, (void**)&pvargArray
); 
 823                 for (l 
= 0; l 
< lUBound
; l
++) 
 825                     ReleaseVariant(pvargArray
); 
 829                 SafeArrayUnaccessData(pvarg
->parray
); 
 834             wxLogWarning(wxT("ReleaseVariant: Array contains non-variant type")); 
 837         // Free the array itself. 
 838         SafeArrayDestroy(pvarg
->parray
); 
 846                     pvarg
->pdispVal
->Release(); 
 850                 SysFreeString(pvarg
->bstrVal
); 
 857             case VT_ERROR
:        // to avoid erroring on an error return from Excel 
 859                 // no work for these types 
 863                 wxLogWarning(wxT("ReleaseVariant: Unknown type")); 
 873 void ShowException(LPOLESTR szMember
, HRESULT hr
, EXCEPINFO 
*pexcep
, unsigned int uiArgErr
) 
 877     switch (GetScode(hr
)) 
 879         case DISP_E_UNKNOWNNAME
: 
 880             wsprintf(szBuf
, L
"%s: Unknown name or named argument.", szMember
); 
 883         case DISP_E_BADPARAMCOUNT
: 
 884             wsprintf(szBuf
, L
"%s: Incorrect number of arguments.", szMember
); 
 887         case DISP_E_EXCEPTION
: 
 888             wsprintf(szBuf
, L
"%s: Error %d: ", szMember
, pexcep
->wCode
); 
 889             if (pexcep
->bstrDescription 
!= NULL
) 
 890                 lstrcat(szBuf
, pexcep
->bstrDescription
); 
 892                 lstrcat(szBuf
, L
"<<No Description>>"); 
 895         case DISP_E_MEMBERNOTFOUND
: 
 896             wsprintf(szBuf
, L
"%s: method or property not found.", szMember
); 
 899         case DISP_E_OVERFLOW
: 
 900             wsprintf(szBuf
, L
"%s: Overflow while coercing argument values.", szMember
); 
 903         case DISP_E_NONAMEDARGS
: 
 904             wsprintf(szBuf
, L
"%s: Object implementation does not support named arguments.", 
 908         case DISP_E_UNKNOWNLCID
: 
 909             wsprintf(szBuf
, L
"%s: The locale ID is unknown.", szMember
); 
 912         case DISP_E_PARAMNOTOPTIONAL
: 
 913             wsprintf(szBuf
, L
"%s: Missing a required parameter.", szMember
); 
 916         case DISP_E_PARAMNOTFOUND
: 
 917             wsprintf(szBuf
, L
"%s: Argument not found, argument %d.", szMember
, uiArgErr
); 
 920         case DISP_E_TYPEMISMATCH
: 
 921             wsprintf(szBuf
, L
"%s: Type mismatch, argument %d.", szMember
, uiArgErr
); 
 925             wsprintf(szBuf
, L
"%s: Unknown error occurred.", szMember
); 
 934 #endif // wxUSE_OLE && !(defined(__BORLANDC__) && (__BORLANDC__ < 0x520)) && !defined(__CYGWIN10__)