HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetSerialPins___VOID__I4__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbrxPin;
    CLR_RT_HeapBlock  hbtxPin;
    CLR_RT_HeapBlock  hbctsPin;
    CLR_RT_HeapBlock  hbrtsPin;

    CLR_UINT32 port, rxPin, txPin, ctsPin, rtsPin;

    port = stack.Arg1().NumericByRef().u4;

    rxPin  = (CLR_UINT32)-1; // GPIO_NONE
    txPin  = (CLR_UINT32)-1; // GPIO_NONE
    ctsPin = (CLR_UINT32)-1; // GPIO_NONE
    rtsPin = (CLR_UINT32)-1; // GPIO_NONE
    
    // COM ports are numbered from 0 up
    if(port >= CPU_USART_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    
    ::CPU_USART_GetPins( port, rxPin, txPin, ctsPin, rtsPin );

    hbrxPin.SetInteger ( (CLR_INT32)rxPin  ); TINYCLR_CHECK_HRESULT(hbrxPin.StoreToReference ( stack.Arg2(),  0 ));
    hbtxPin.SetInteger ( (CLR_INT32)txPin  ); TINYCLR_CHECK_HRESULT(hbtxPin.StoreToReference ( stack.Arg3(),  0 ));
    hbctsPin.SetInteger( (CLR_INT32)ctsPin ); TINYCLR_CHECK_HRESULT(hbctsPin.StoreToReference( stack.Arg4(),  0 ));
    hbrtsPin.SetInteger( (CLR_INT32)rtsPin ); TINYCLR_CHECK_HRESULT(hbrtsPin.StoreToReference( stack.ArgN(5), 0 ));
    

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetLCDMetrics___VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();


    CLR_RT_HeapBlock  hbLength;
    CLR_RT_HeapBlock  hbWidth;
    CLR_RT_HeapBlock  hbBitPP;
    CLR_RT_HeapBlock  hbOrientation;

    CLR_UINT32        length, width, bitPP, orientation;

    width  = LCD_SCREEN_WIDTH;
    length = LCD_SCREEN_HEIGHT;
    bitPP  = LCD_SCREEN_BPP;
    orientation = LCD_SCREEN_ORIENTATION;

    hbLength.SetInteger( (CLR_INT32)length );TINYCLR_CHECK_HRESULT(hbLength.StoreToReference( stack.Arg1(), 0 ));
    hbWidth.SetInteger (( CLR_INT32)width  );TINYCLR_CHECK_HRESULT(hbWidth.StoreToReference ( stack.Arg2(), 0 ));

    hbBitPP.SetInteger( (CLR_INT32)bitPP );             TINYCLR_CHECK_HRESULT(hbBitPP.StoreToReference( stack.Arg3(), 0 ));
    hbOrientation.SetInteger( (CLR_INT32)orientation ); TINYCLR_CHECK_HRESULT(hbOrientation.StoreToReference( stack.Arg4(), 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetBaudRateBoundary___VOID__I4__BYREF_U4__BYREF_U4( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbmaxBR;
    CLR_RT_HeapBlock  hbminBR;

    CLR_UINT32 port, maxBR, minBR;

    port = stack.Arg1().NumericByRef().u4;

    maxBR = (CLR_UINT32)0; 
    minBR = (CLR_UINT32)0; 
    
    // COM ports are numbered from 0 up
    if(port >= CPU_USART_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }

    ::CPU_USART_GetBaudrateBoundary( port, maxBR, minBR );

    hbmaxBR.SetInteger( (CLR_INT32)maxBR ); TINYCLR_CHECK_HRESULT(hbmaxBR.StoreToReference( stack.Arg2(), 0 ));
    hbminBR.SetInteger( (CLR_INT32)minBR ); TINYCLR_CHECK_HRESULT(hbminBR.StoreToReference( stack.Arg3(), 0 ));
  

    TINYCLR_NOCLEANUP();


}
//--// SPI
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetSpiPins___VOID__MicrosoftSPOTHardwareSPISPImodule__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();

    CLR_RT_HeapBlock  hbmsk;
    CLR_RT_HeapBlock  hbmiso;
    CLR_RT_HeapBlock  hbmosi;
    
    CLR_UINT32        port, msk, miso, mosi;

    msk  = (CLR_UINT32)-1; // GPIO_NONE
    miso = (CLR_UINT32)-1; // GPIO_NONE
    mosi = (CLR_UINT32)-1; // GPIO_NONE
    
    port = stack.Arg1().NumericByRef().u4;

    // SPI ports are numbered from 0 up
    if(port >= CPU_SPI_PortsCount())
    {
        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
    }
    
    ::CPU_SPI_GetPins( port, msk, miso, mosi );

    hbmsk.SetInteger ( (CLR_INT32)msk  ); TINYCLR_CHECK_HRESULT(hbmsk .StoreToReference( stack.Arg2(), 0 ));
    hbmiso.SetInteger( (CLR_INT32)miso ); TINYCLR_CHECK_HRESULT(hbmiso.StoreToReference( stack.Arg3(), 0 ));
    hbmosi.SetInteger( (CLR_INT32)mosi ); TINYCLR_CHECK_HRESULT(hbmosi.StoreToReference( stack.Arg4(), 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_native_Microsoft_SPOT_Hardware_SystemInfo::GetSystemVersion___STATIC__VOID__BYREF_I4__BYREF_I4__BYREF_I4__BYREF_I4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();
    {
        CLR_RT_HeapBlock hbMajor;
        CLR_RT_HeapBlock hbMinor;
        CLR_RT_HeapBlock hbBuild;
        CLR_RT_HeapBlock hbRevision;

        MfReleaseInfo releaseInfo;

        Solution_GetReleaseInfo( releaseInfo );

        hbMajor.SetInteger( releaseInfo.version.usMajor );
        TINYCLR_CHECK_HRESULT(hbMajor.StoreToReference( stack.Arg0(), 0 ));

        hbMinor.SetInteger( releaseInfo.version.usMinor );
        TINYCLR_CHECK_HRESULT(hbMinor.StoreToReference( stack.Arg1(), 0 ));

        hbBuild.SetInteger( releaseInfo.version.usBuild );
        TINYCLR_CHECK_HRESULT(hbBuild.StoreToReference( stack.Arg2(), 0 ));

        hbRevision.SetInteger( releaseInfo.version.usRevision );
        TINYCLR_CHECK_HRESULT(hbRevision.StoreToReference( stack.Arg3(), 0 ));
    }
    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::MarshalSockAddress( CLR_RT_HeapBlock& blkDst, const struct SOCK_sockaddr* addrSrc, CLR_UINT32 addrLenSrc )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock_Array* arr = NULL;

    CLR_RT_HeapBlock blkArr; blkArr.SetObjectReference( NULL );
    CLR_RT_ProtectFromGC gc( blkArr );
    SOCK_sockaddr_in* dst;
    SOCK_sockaddr_in* src = (SOCK_sockaddr_in*)addrSrc;
        
    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( blkArr, addrLenSrc, g_CLR_RT_WellKnownTypes.m_UInt8 ));
    
    arr = blkArr.DereferenceArray();

    _ASSERTE(arr);

    dst = (SOCK_sockaddr_in*)arr->GetFirstElement();

    dst->sin_family           = SwapEndianIfBEc16(src->sin_family);
    dst->sin_port             = src->sin_port;
    dst->sin_addr.S_un.S_addr = src->sin_addr.S_un.S_addr;

    memcpy(dst->sin_zero, src->sin_zero, sizeof(dst->sin_zero));

    _ASSERTE(blkDst.DataType() == DATATYPE_BYREF || blkDst.DataType() == DATATYPE_ARRAY_BYREF);

    TINYCLR_CHECK_HRESULT(blkArr.StoreToReference( blkDst, 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Interop_Marshal_StoreRef( CLR_RT_StackFrame &stackFrame, void *pVoidHeapBlock, UINT32 paramIndex )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();
    CLR_RT_HeapBlock *pHeapBlock = (CLR_RT_HeapBlock *)pVoidHeapBlock;
    TINYCLR_CHECK_HRESULT(pHeapBlock->StoreToReference( stackFrame.ArgN(paramIndex), 0 ));
    TINYCLR_NOCLEANUP();
}
//--// I2C
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeGetI2CPins___VOID__BYREF_MicrosoftSPOTHardwareCpuPin__BYREF_MicrosoftSPOTHardwareCpuPin( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
    CLR_RT_HeapBlock  hbscl;
    CLR_RT_HeapBlock  hbsda;
    CLR_UINT32        scl, sda;

    scl = (CLR_UINT32)-1; // GPIO_NONE
    sda = (CLR_UINT32)-1; // GPIO_NONE

    ::I2C_Internal_GetPins( scl, sda );

    hbscl.SetInteger( (CLR_INT32)scl ); TINYCLR_CHECK_HRESULT(hbscl.StoreToReference( stack.Arg1(), 0 ));
    hbsda.SetInteger( (CLR_INT32)sda ); TINYCLR_CHECK_HRESULT(hbsda.StoreToReference( stack.Arg2(), 0 ));

    TINYCLR_NOCLEANUP();

}
HRESULT Library_spot_hardware_native_Microsoft_SPOT_Hardware_HardwareProvider::NativeIsSupportedBaudRate___BOOLEAN__I4__BYREF_U4( CLR_RT_StackFrame& stack )
{
	TINYCLR_HEADER();
    CLR_RT_HeapBlock  hbBR;
    CLR_UINT32        port;
   
    CLR_UINT32        SupportedBaudrate;

    port              = stack.Arg1().NumericByRef().u4;

    TINYCLR_CHECK_HRESULT(hbBR.LoadFromReference( stack.Arg2() ));
    SupportedBaudrate = hbBR.NumericByRef().u4;

    if (CPU_USART_IsBaudrateSupported(port,SupportedBaudrate) == TRUE)
        stack.SetResult_Boolean( true );
    else
        stack.SetResult_Boolean( false );

    hbBR.SetInteger( (CLR_UINT32)SupportedBaudrate );
    TINYCLR_CHECK_HRESULT(hbBR.StoreToReference( stack.Arg2(), 0 ));        

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::MarshalSockAddress( CLR_RT_HeapBlock& blkDst, const struct SOCK_sockaddr* addrSrc, CLR_UINT32 addrLenSrc )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock_Array* arr = NULL;

    CLR_RT_HeapBlock blkArr; blkArr.SetObjectReference( NULL );
    CLR_RT_ProtectFromGC gc( blkArr );
        
    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( blkArr, addrLenSrc, g_CLR_RT_WellKnownTypes.m_UInt8 ));
    
    arr = blkArr.DereferenceArray();

    _ASSERTE(arr);

    memcpy( arr->GetFirstElement(), addrSrc, addrLenSrc );

    _ASSERTE(blkDst.DataType() == DATATYPE_BYREF || blkDst.DataType() == DATATYPE_ARRAY_BYREF);

    TINYCLR_CHECK_HRESULT(blkArr.StoreToReference( blkDst, 0 ));

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::ioctl___STATIC__VOID__OBJECT__U4__BYREF_U4( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock* socket = stack.Arg0().Dereference();
    CLR_INT32 handle;
    CLR_INT32 cmd     = stack.Arg1().NumericByRef().s4;
    CLR_RT_HeapBlock blkArg;
    CLR_INT32 ret;

    FAULT_ON_NULL(socket);
    handle = socket[ FIELD__m_Handle ].NumericByRef().s4;

    _SIDE_ASSERTE(SUCCEEDED(blkArg.LoadFromReference( stack.Arg2() )));

    ret = SOCK_ioctl( handle, cmd, (CLR_INT32*)&blkArg.NumericByRef().s4 );
    
    TINYCLR_CHECK_HRESULT(ThrowOnError( stack, ret ));

    _SIDE_ASSERTE(SUCCEEDED(blkArg.StoreToReference( stack.Arg2(), 0 )));

    TINYCLR_NOCLEANUP();
}
HRESULT CLR_RT_HeapBlock_Array::Copy( CLR_RT_HeapBlock_Array* arraySrc, int indexSrc, CLR_RT_HeapBlock_Array* arrayDst, int indexDst, int length )
{
    NATIVE_PROFILE_CLR_CORE();
    TINYCLR_HEADER();

    if(length)
    {
        int numElemSrc = arraySrc->m_numOfElements;
        int numElemDst = arrayDst->m_numOfElements;

        if(length   < 0                   ||
           indexSrc < 0                   ||
           indexDst < 0                   ||
           length + indexSrc > numElemSrc ||
           length + indexDst > numElemDst  )
        {
            TINYCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE);
        }

        //
        // Copy of an array on itself.
        //
        if(arraySrc == arrayDst && indexSrc == indexDst) TINYCLR_SET_AND_LEAVE(S_OK);

        if(arraySrc->SameHeader( *arrayDst ))
        {
            CLR_UINT8* dataSrc  = arraySrc->GetFirstElement();
            CLR_UINT8* dataDst  = arrayDst->GetFirstElement();
            CLR_UINT8  sizeElem = arraySrc->m_sizeOfElement;

            dataSrc += indexSrc * sizeElem;
            dataDst += indexDst * sizeElem;

            if(!arraySrc->m_fReference)
            {
                memmove( dataDst, dataSrc, length * sizeElem );
            }
            else
            {
                CLR_RT_HeapBlock* ptrSrc = (CLR_RT_HeapBlock*)dataSrc;
                CLR_RT_HeapBlock* ptrDst = (CLR_RT_HeapBlock*)dataDst;
                int               incr;

                if(arraySrc == arrayDst && ptrSrc < ptrDst)
                {
                    incr    =       -1;
                    ptrSrc += length-1;
                    ptrDst += length-1;
                }
                else
                {
                    incr = 1;
                }

                for(int i=0; i<length; i++, ptrSrc += incr, ptrDst += incr)
                {
                    TINYCLR_CHECK_HRESULT(ptrDst->Reassign( *ptrSrc ));
                }
            }
        }
        else if(arraySrc->m_fReference && arrayDst->m_fReference)
        {
            CLR_RT_TypeDescriptor descSrc;
            CLR_RT_TypeDescriptor descDst;
            CLR_RT_HeapBlock*     ptrSrc   = (CLR_RT_HeapBlock*)arraySrc->GetElement( indexSrc );
            CLR_RT_HeapBlock*     ptrDst   = (CLR_RT_HeapBlock*)arrayDst->GetElement( indexDst );
            
            TINYCLR_CHECK_HRESULT(descDst.InitializeFromObject( *arrayDst )); descDst.GetElementType( descDst );

            for(int i=0; i<length; i++, ptrSrc++, ptrDst++)
            {
                if(ptrSrc->DataType() == DATATYPE_OBJECT && ptrSrc->Dereference() == NULL)
                {
                    ;
                }
                else
                {
                    TINYCLR_CHECK_HRESULT(descSrc.InitializeFromObject( *ptrSrc ));

                    if(CLR_RT_ExecutionEngine::IsInstanceOf( descSrc, descDst ) == false)
                    {
                        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_CAST);
                    }
                }

                TINYCLR_CHECK_HRESULT(ptrDst->Reassign( *ptrSrc ));
            }
        }
        else
        {
            CLR_RT_TypeDescriptor descSrc;
            CLR_RT_TypeDescriptor descDst;
            CLR_RT_HeapBlock      ref;
            CLR_RT_HeapBlock      elem; elem.SetObjectReference( NULL );
            CLR_RT_ProtectFromGC  gc( elem ); 

            TINYCLR_CHECK_HRESULT(descDst.InitializeFromObject( *arrayDst )); descDst.GetElementType( descDst );

            for(int i=0; i<length; i++)
            {
                ref.InitializeArrayReferenceDirect( *arraySrc, indexSrc++ ); TINYCLR_CHECK_HRESULT(elem.LoadFromReference( ref ));

                if(elem.DataType() == DATATYPE_OBJECT && elem.Dereference() == NULL)
                {
                    ;
                }
                else
                {
                    TINYCLR_CHECK_HRESULT(descSrc.InitializeFromObject( elem ));

                    if(CLR_RT_ExecutionEngine::IsInstanceOf( descSrc, descDst ) == false)
                    {
                        TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_CAST);
                    }
                }

                ref.InitializeArrayReferenceDirect( *arrayDst, indexDst++ ); TINYCLR_CHECK_HRESULT(elem.StoreToReference( ref, 0 ));
            }
        }
    }

    TINYCLR_NOCLEANUP();
}
HRESULT Library_spot_net_native_Microsoft_SPOT_Net_SocketNative::getaddrinfo___STATIC__VOID__STRING__BYREF_STRING__BYREF_SZARRAY_SZARRAY_U1( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    LPCSTR szName = stack.Arg0().RecoverString();
    struct SOCK_addrinfo hints;
    struct SOCK_addrinfo* addr = NULL;
    struct SOCK_addrinfo* addrT;
    CLR_UINT32        cAddresses = 0;
    CLR_RT_HeapBlock* pAddress;
    CLR_INT32         timeout_ms = 30000;
    CLR_RT_HeapBlock  hbTimeout;
    CLR_INT32         ret;
    bool              fRes = true;
    CLR_INT64*        timeout;

    hbTimeout.SetInteger( timeout_ms );

    TINYCLR_CHECK_HRESULT(stack.SetupTimeout( hbTimeout, timeout ));

    do
    {
        memset( &hints, 0, sizeof(hints) );

        ret = SOCK_getaddrinfo( szName, NULL, &hints, &addr );

        if(ret == SOCK_SOCKET_ERROR)
        {
            if(SOCK_getlasterror() == SOCK_EWOULDBLOCK)
            {
                // non-blocking - allow other threads to run while we wait for handle activity
                TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.WaitEvents( stack.m_owningThread, *timeout, CLR_RT_ExecutionEngine::c_Event_Socket, fRes ));
            }
            else
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    while(fRes);
    
    // timeout expired
    if(!fRes)
    {
        ret = SOCK_SOCKET_ERROR;
        
        ThrowError( stack, SOCK_ETIMEDOUT );
    
        TINYCLR_SET_AND_LEAVE( CLR_E_PROCESS_EXCEPTION );
    }

    // getaddrinfo returns a winsock error code rather than SOCK_SOCKET_ERROR, so pass this on to the exception handling
    if(ret != 0)
    {
        ThrowError( stack, ret );
        TINYCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION);
    }

    {
        CLR_RT_HeapBlock  hbCanonicalName;
        CLR_RT_HeapBlock  hbAddresses;
        
        hbCanonicalName.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc( hbCanonicalName );

        hbAddresses.SetObjectReference( NULL );
        CLR_RT_ProtectFromGC gc2( hbAddresses );

        for(int pass = 0; pass < 2; pass++)
        {                                    
            cAddresses = 0;

            for(addrT = addr; addrT != NULL; addrT = addrT->ai_next)
            {
                if(pass == 1)
                {
                    if(addrT->ai_canonname && addrT->ai_canonname[ 0 ])
                    {
                        //allocate return string
                        TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbCanonicalName, addrT->ai_canonname ));
                        TINYCLR_CHECK_HRESULT(hbCanonicalName.StoreToReference( stack.Arg1(), 0 ));
                    }

                    //allocate address and store into array
                    pAddress = (CLR_RT_HeapBlock*)hbAddresses.DereferenceArray()->GetElement( cAddresses );

                    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( *pAddress, (CLR_UINT32)addrT->ai_addrlen, g_CLR_RT_WellKnownTypes.m_UInt8 ));

                    //copy address.
                    memcpy( pAddress->DereferenceArray()->GetFirstElement(), addrT->ai_addr, addrT->ai_addrlen );
                }
                                
                cAddresses++;
            }
                            
            if(pass == 0)
            {
                //allocate array of byte arrays
                CLR_RT_ReflectionDef_Index idx;

                idx.m_kind               = REFLECTION_TYPE;
                idx.m_levels             = 2;
                idx.m_data.m_type.m_data = g_CLR_RT_WellKnownTypes.m_UInt8.m_data;

                TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( hbAddresses, cAddresses, idx ));

                TINYCLR_CHECK_HRESULT(hbAddresses.StoreToReference( stack.Arg2(), 0 ));                
            }
        }    
    }

    stack.PopValue();       // Timeout
    
    TINYCLR_CLEANUP();

    if( addr ) SOCK_freeaddrinfo( addr );

    TINYCLR_CLEANUP_END();
}
HRESULT Library_spot_net_security_native_Microsoft_SPOT_Net_Security_SslNative::ParseCertificate___STATIC__VOID__SZARRAY_U1__STRING__BYREF_STRING__BYREF_STRING__BYREF_mscorlibSystemDateTime__BYREF_mscorlibSystemDateTime( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_NETWORK();
    TINYCLR_HEADER();

    CLR_RT_HeapBlock_Array* arrData    = stack.Arg0().DereferenceArray(); 
    CLR_UINT8*              certBytes;
    CLR_RT_HeapBlock        hbIssuer;
    CLR_RT_HeapBlock        hbSubject;
    CLR_RT_ProtectFromGC    gc1( hbIssuer  );
    CLR_RT_ProtectFromGC    gc2( hbSubject );
    X509CertData            cert;
    CLR_INT64*              val;
    CLR_INT64               tzOffset;
    SYSTEMTIME              st;
    INT32                   standardBias;
    CLR_RT_HeapBlock*       hbPwd     = stack.Arg1().DereferenceString();
    LPCSTR                  szPwd;


    FAULT_ON_NULL_ARG(hbPwd);

    szPwd = hbPwd->StringText();

    CLR_RT_Memory::ZeroFill( &cert, sizeof(cert) );

    FAULT_ON_NULL(arrData);

    certBytes = arrData->GetFirstElement();

    if(!SSL_ParseCertificate( (const char*)certBytes, arrData->m_numOfElements, szPwd, &cert )) TINYCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);

    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbIssuer, cert.Issuer ));
    TINYCLR_CHECK_HRESULT(hbIssuer.StoreToReference( stack.Arg2(), 0 ));

    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_String::CreateInstance( hbSubject, cert.Subject ));
    TINYCLR_CHECK_HRESULT(hbSubject.StoreToReference( stack.Arg3(), 0 ));

    st.wYear         = cert.EffectiveDate.year;
    st.wMonth        = cert.EffectiveDate.month;
    st.wDay          = cert.EffectiveDate.day;
    st.wHour         = cert.EffectiveDate.hour;
    st.wMinute       = cert.EffectiveDate.minute;
    st.wSecond       = cert.EffectiveDate.second;
    st.wMilliseconds = cert.EffectiveDate.msec;

    standardBias     = Time_GetTimeZoneOffset();
    standardBias    *= TIME_CONVERSION__ONEMINUTE;

    val = Library_corlib_native_System_DateTime::GetValuePtr( stack.Arg4() );
    *val = Time_FromSystemTime( &st );

    tzOffset = cert.EffectiveDate.tzOffset;

    // adjust for timezone differences
    if(standardBias != tzOffset)
    {
        *val += tzOffset - standardBias; 
    }

    st.wYear         = cert.ExpirationDate.year;
    st.wMonth        = cert.ExpirationDate.month;
    st.wDay          = cert.ExpirationDate.day;
    st.wHour         = cert.ExpirationDate.hour;
    st.wMinute       = cert.ExpirationDate.minute;
    st.wSecond       = cert.ExpirationDate.second;
    st.wMilliseconds = cert.ExpirationDate.msec;
    
    val = Library_corlib_native_System_DateTime::GetValuePtr( stack.ArgN( 5 ) );
    *val = Time_FromSystemTime( &st );

    tzOffset = cert.ExpirationDate.tzOffset;
    
    if(standardBias != tzOffset)
    {
       *val += tzOffset - standardBias; 
    }

    TINYCLR_NOCLEANUP();
}