/*
 * This file was generated automatically by ExtUtils::ParseXS version 3.28 from the
 * contents of API.xs. Do not edit this file, edit API.xs instead.
 *
 *    ANY CHANGES MADE HERE WILL BE LOST!
 *
 */

/*
    # Win32::API - Perl Win32 API Import Facility
    #
    # Author: Aldo Calpini <dada@perl.it>
    # Author: Daniel Dragan <bulk88@hotmail.com>
    # Maintainer: Cosimo Streppone <cosimo@cpan.org>
    #
    # $Id$
 */

#define  WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <memory.h>
#define PERL_NO_GET_CONTEXT
#define NO_XSLOCKS
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#define CROAK croak
//#include <emmintrin.h>
#include "API.h"

/*
 * some Perl macros for backward compatibility
 */
#ifdef NT_BUILD_NUMBER
#define boolSV(b) ((b) ? &sv_yes : &sv_no)
#endif

#ifndef PL_na
#	define PL_na na
#endif

#ifndef SvPV_nolen
#	define SvPV_nolen(sv) SvPV(sv, PL_na)
#endif

#ifndef call_pv
#	define call_pv(name, flags) perl_call_pv(name, flags)
#endif

#ifndef call_method
#	define call_method(name, flags) perl_call_method(name, flags)
#endif

#define MODNAME "Win32::API"

/*added because of http://www.cpantesters.org/cpan/report/fd483be1-6c0a-1014-9049-f37bd871b27e
  but the below isn't the problem to above report, memset func ptr being
  NULL in the DLL is */
#if defined(_MSC_VER) && defined(__GNUC__)
#  error A compiler can be either _MSC_VER or __GNUC__, not both
#endif

/*get rid of CRT startup code on MSVC, we use exactly 3 CRT functions
memcpy, memmov, and wcslen, neither require any specific initialization other than
loading the CRT DLL (SSE probing on modern CRTs is done when CRT DLL is loaded
not when a random DLL subscribes to the the CRT), Mingw has more startup code
than MSVC does, so I (bulk88) will leave Mingw's CRT startup code in*/
#ifdef _MSC_VER
BOOL WINAPI _DllMainCRTStartup(
    HINSTANCE hinstDLL,
    DWORD fdwReason,
    LPVOID lpReserved )
{
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
            if(!DisableThreadLibraryCalls(hinstDLL)) return FALSE;
            break;
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}
#endif

#ifdef _MSC_VER
extern __declspec(selectany) /*enable comdat folding for this symbol in msvc*/
#endif
PORTALIGN(1) const char bad_esp_msg [] = "Win32::API a function was called with the wrong prototype "
"and caused a C stack inconsistency EBP=%p ESP=%p" ;

#ifdef _MSC_VER
extern __declspec(selectany) /*enable comdat folding for this symbol in msvc*/
#endif
PORTALIGN(1) const struct {
    char Unpack [sizeof("Win32::API::Type::Unpack")];
    char Pack [sizeof("Win32::API::Type::Pack")];
    char ck_type [sizeof("Win32::API::Struct::ck_type")];
} Param3FuncNames = {
    "Win32::API::Type::Unpack",
    "Win32::API::Type::Pack",
    "Win32::API::Struct::ck_type"
};
#define PARAM3_UNPACK ((int)((char*)(&Param3FuncNames.Unpack) - (char*)&Param3FuncNames))
#define PARAM3_PACK ((int)((char*)(&Param3FuncNames.Pack) - (char*)&Param3FuncNames))
#define PARAM3_CK_TYPE ((int)((char*)(&Param3FuncNames.ck_type) - (char*)&Param3FuncNames))
STATIC void pointerCall3Param(pTHX_ SV * sv1, SV * sv2, SV * sv3, int func_offset) {
    //for Type::Un/Pack obj, type, param, for ::Struct::ck_type param, proto, param_num
	dSP;
	W32APUSHMARK(SP);
    STATIC_ASSERT(CALL_PL_ST_EXTEND >= 3); //EXTEND replacement
    PUSHs(sv1);
    PUSHs(sv2);
	PUSHs(sv3);
	PUTBACK;
	call_pv((char*)&Param3FuncNames+func_offset, G_VOID|G_DISCARD);
}

STATIC SV * getTarg(pTHX) {
    dXSTARG;
    PREP_SV_SET(TARG);
    SvOK_off(TARG);
    return TARG;
}

/* Convert wide character string to mortal SV.  Use UTF8 encoding
 * if the string cannot be represented in the system codepage.
 * If wlen isn't -1 (calculate length), wlen must include the null wchar
 * in its count of wchars, and null wchar must be last wchar
 */
STATIC void w32sv_setwstr(pTHX_ SV * sv, WCHAR *wstr, INT_PTR wlenparam) {
    char * dest;
    BOOL use_default = FALSE;
    BOOL * use_default_ptr = &use_default;    
    UINT CodePage;
    DWORD dwFlags;
    int len;
    /* note 0xFFFFFFFFFFFFFFFF and 0xFFFFFFFF truncate to the same here on x64*/
    int wlen = (int) wlenparam; 
    WCHAR * tempwstr = NULL;
    
    /*can't pass -1 to WCTMB because of sv pv to wstr comparison and copy */
    if(wlen == -1) {
        wlen = (int)wcslen(wstr)+1;
    }
    /*a Win32 API might claiming to create null terminated, length counted, string
    but infact is creating non terminated, length counted, strings, catch it*/
    if(wstr[wlen-1] != L'\0') croak("(XS) " MODNAME "::w32sv_setwstr panic: %s", "wide string is not null terminated\n");
#ifdef _WIN64     /* WCTMB only takes 32 bits ints*/
    if(wlenparam > (INT_PTR) INT_MAX && wlenparam != 0xFFFFFFFF) croak("(XS) " MODNAME "::w32sv_setwstr panic: %s", "string overflow\n");
#endif
    if(
/* SvPVX in head, not ANY/body, added in 5.9.3, dont crash */
#if (PERL_VERSION_LE(5, 9, 2))
        SvTYPE(sv) >= SVt_PV &&
#endif
       ((WCHAR *)SvPVX(sv)) == wstr) {//WCTMB bufs cant overlap
        //dont trip MEM_WRAP_CHECK macro that is a pointless runtime assert
        Newx(*(char**)&tempwstr, (wlen*sizeof(WCHAR)), char);
        wstr = memcpy(tempwstr, wstr, wlen * sizeof(WCHAR));
    }
    CodePage = CP_ACP;
    dwFlags = WC_NO_BEST_FIT_CHARS;
    
    retry:
    len = WideCharToMultiByte(CodePage, dwFlags, wstr, wlen, NULL, 0, NULL, NULL);
    dest = sv_grow(sv, (STRLEN)len); /*access vio on macro*/
    len = WideCharToMultiByte(CodePage, dwFlags, wstr, wlen, dest, len, NULL, use_default_ptr);
    if (use_default) {
        SvUTF8_on(sv);
        use_default = FALSE;
        use_default_ptr = NULL;
        /*this branch will never be taken again*/
        CodePage = CP_UTF8;
        dwFlags = 0;
        goto retry;
    }
    /* Shouldn't really ever fail since we ask for the required length first, but who knows... */
    if (len) {
        SvPOK_on(sv);
        SvCUR_set(sv, len-1);
    }
    else {
        SvOK_off(sv);
    }
    if(tempwstr) Safefree(tempwstr);
}

#if defined(_M_AMD64) || defined(__x86_64)
#include "call_x86_64.h"
#elif defined(_M_IX86) || defined(__i386)
#include "call_i686.h"
#else
#error "Don't know what architecture I'm on."
#endif

#define MY_CXT_KEY "Win32::API_guts"
typedef struct {
    SV * sentinal;
    /* the *Key vars are all leaked SVs since MY_CXT struct's contents is never freeded
    bulk88 doesn't know where/when to call a dtor on these */
    /* obsolete, now in APICONTROL
    SV * controlKey;
    SV * intypesKey;
    SV * inKey;
    */
} my_cxt_t;

START_MY_CXT

/* returns cxt->sentinal */
static SV * initSharedKeys (pTHX_ my_cxt_t * cxt) {
    /* obsolete, now in APICONTROL
    cxt->controlKey = newSVpvs_share("control");
    cxt->intypesKey = newSVpvs_share("intypes");
    cxt->inKey = newSVpvs_share("in");
    */
    cxt->sentinal = get_sv("Win32::API::sentinal", 1); /* must be 1 b/c used in CLONE and BOOT */
    return cxt->sentinal;
}

/* declare as 5 member, not normal 8 to save image space*/
const static struct {
	int (*svt_get)(SV* sv, MAGIC* mg);
	int (*svt_set)(SV* sv, MAGIC* mg);
	U32 (*svt_len)(SV* sv, MAGIC* mg);
	int (*svt_clear)(SV* sv, MAGIC* mg);
	int (*svt_free)(SV* sv, MAGIC* mg);
} vtbl_API = {
	NULL, NULL, NULL, NULL, NULL
};

/* gets hidden magic SV from SV, returns NULL if not there, return is not refcnt++ed*/
STATIC SV * getMgSV(pTHX_ SV * sv) {
	MAGIC * mg;
	if(SvRMAGICAL(sv)) { /* implies SvTYPE  >= SVt_PVMG */
		mg = mg_findext(sv, PERL_MAGIC_ext, (const MGVTBL * const)&vtbl_API);
		if(mg) {
			return mg->mg_obj;
		}
		else return NULL;
	}
	else return NULL;
}

/* puts newsv, refcnt++ed (caller doesn't have to do it), in sv as hidden magic SV */
STATIC void setMgSV(pTHX_ SV * sv, SV * newsv) {
	MAGIC * mg;
	if(SvRMAGICAL(sv)) { /* implies SvTYPE  >= SVt_PVMG */
		mg = mg_findext(sv, PERL_MAGIC_ext, (const MGVTBL * const)&vtbl_API);
		if(mg) {
			SV * oldsv;
			SvREFCNT_inc_simple_void_NN(newsv);
			oldsv = mg->mg_obj;
			mg->mg_obj = newsv;
			SvREFCNT_dec(oldsv);
		} else {
			goto addmg;
		}
	}
	else {
		addmg:
		sv_magicext(sv,newsv,PERL_MAGIC_ext,(const MGVTBL * const)&vtbl_API,NULL,0);
	}
}

#include "Call.c"

#ifndef PERL_UNUSED_VAR
#  define PERL_UNUSED_VAR(var) if (0) var = var
#endif

#ifndef dVAR
#  define dVAR		dNOOP
#endif


/* This stuff is not part of the API! You have been warned. */
#ifndef PERL_VERSION_DECIMAL
#  define PERL_VERSION_DECIMAL(r,v,s) (r*1000000 + v*1000 + s)
#endif
#ifndef PERL_DECIMAL_VERSION
#  define PERL_DECIMAL_VERSION \
	  PERL_VERSION_DECIMAL(PERL_REVISION,PERL_VERSION,PERL_SUBVERSION)
#endif
#ifndef PERL_VERSION_GE
#  define PERL_VERSION_GE(r,v,s) \
	  (PERL_DECIMAL_VERSION >= PERL_VERSION_DECIMAL(r,v,s))
#endif
#ifndef PERL_VERSION_LE
#  define PERL_VERSION_LE(r,v,s) \
	  (PERL_DECIMAL_VERSION <= PERL_VERSION_DECIMAL(r,v,s))
#endif

/* XS_INTERNAL is the explicit static-linkage variant of the default
 * XS macro.
 *
 * XS_EXTERNAL is the same as XS_INTERNAL except it does not include
 * "STATIC", ie. it exports XSUB symbols. You probably don't want that
 * for anything but the BOOT XSUB.
 *
 * See XSUB.h in core!
 */


/* TODO: This might be compatible further back than 5.10.0. */
#if PERL_VERSION_GE(5, 10, 0) && PERL_VERSION_LE(5, 15, 1)
#  undef XS_EXTERNAL
#  undef XS_INTERNAL
#  if defined(__CYGWIN__) && defined(USE_DYNAMIC_LOADING)
#    define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name)
#    define XS_INTERNAL(name) STATIC XSPROTO(name)
#  endif
#  if defined(__SYMBIAN32__)
#    define XS_EXTERNAL(name) EXPORT_C XSPROTO(name)
#    define XS_INTERNAL(name) EXPORT_C STATIC XSPROTO(name)
#  endif
#  ifndef XS_EXTERNAL
#    if defined(HASATTRIBUTE_UNUSED) && !defined(__cplusplus)
#      define XS_EXTERNAL(name) void name(pTHX_ CV* cv __attribute__unused__)
#      define XS_INTERNAL(name) STATIC void name(pTHX_ CV* cv __attribute__unused__)
#    else
#      ifdef __cplusplus
#        define XS_EXTERNAL(name) extern "C" XSPROTO(name)
#        define XS_INTERNAL(name) static XSPROTO(name)
#      else
#        define XS_EXTERNAL(name) XSPROTO(name)
#        define XS_INTERNAL(name) STATIC XSPROTO(name)
#      endif
#    endif
#  endif
#endif

/* perl >= 5.10.0 && perl <= 5.15.1 */


/* The XS_EXTERNAL macro is used for functions that must not be static
 * like the boot XSUB of a module. If perl didn't have an XS_EXTERNAL
 * macro defined, the best we can do is assume XS is the same.
 * Dito for XS_INTERNAL.
 */
#ifndef XS_EXTERNAL
#  define XS_EXTERNAL(name) XS(name)
#endif
#ifndef XS_INTERNAL
#  define XS_INTERNAL(name) XS(name)
#endif

/* Now, finally, after all this mess, we want an ExtUtils::ParseXS
 * internal macro that we're free to redefine for varying linkage due
 * to the EXPORT_XSUB_SYMBOLS XS keyword. This is internal, use
 * XS_EXTERNAL(name) or XS_INTERNAL(name) in your code if you need to!
 */

#undef XS_EUPXS
#if defined(PERL_EUPXS_ALWAYS_EXPORT)
#  define XS_EUPXS(name) XS_EXTERNAL(name)
#else
   /* default to internal */
#  define XS_EUPXS(name) XS_INTERNAL(name)
#endif

#ifndef PERL_ARGS_ASSERT_CROAK_XS_USAGE
#define PERL_ARGS_ASSERT_CROAK_XS_USAGE assert(cv); assert(params)

/* prototype to pass -Wmissing-prototypes */
STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params);

STATIC void
S_croak_xs_usage(const CV *const cv, const char *const params)
{
    const GV *const gv = CvGV(cv);

    PERL_ARGS_ASSERT_CROAK_XS_USAGE;

    if (gv) {
        const char *const gvname = GvNAME(gv);
        const HV *const stash = GvSTASH(gv);
        const char *const hvname = stash ? HvNAME(stash) : NULL;

        if (hvname)
	    Perl_croak_nocontext("Usage: %s::%s(%s)", hvname, gvname, params);
        else
	    Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
    } else {
        /* Pants. I don't think that it should be possible to get here. */
	Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
    }
}
#undef  PERL_ARGS_ASSERT_CROAK_XS_USAGE

#define croak_xs_usage        S_croak_xs_usage

#endif

/* NOTE: the prototype of newXSproto() is different in versions of perls,
 * so we define a portable version of newXSproto()
 */
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) (PL_Sv=(SV*)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV*)PL_Sv)
#endif /* !defined(newXS_flags) */

#if PERL_VERSION_LE(5, 21, 5)
#  define newXS_deffile(a,b) Perl_newXS(aTHX_ a,b,file)
#else
#  define newXS_deffile(a,b) Perl_newXS_deffile(aTHX_ a,b)
#endif

#if IVSIZE == 4
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_Win32__API_UseMI64); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_UseMI64)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
    SV * self;
    APICONTROL * control;
    if (items < 1 || items > 2)
       croak_xs_usage(cv,  "self [, FlagBool]");
    self = ST(0);
	if (!(SvROK(self) && ((self = SvRV(self)),
                          (SvFLAGS(self) & (SVs_OBJECT|SVs_RMG|SVt_MASK))
                          == (SVs_OBJECT|SVs_RMG|SVt_PVMG))))
    /* I dont think an upgrade to > SVt_PVMG, like SVt_PVLV, will ever happen
      unless someone went inside the object */
    /* add a SvCUR APICONTROL check ?? */
        croak("%s: %s is not of type Win32::API [::More]",
			"Win32::API::UseMI64",
			"self");
    //key always exists
    control = (APICONTROL *)SvPVX(self);
    PUSHs(boolSV(control->UseMI64)); //ST(0) now gone
    PUTBACK;

    if(items == 2){
        control->UseMI64 = sv_true(ST(1));
    }
    return; /* dont call PUTBACK again */
	PUTBACK;
	return;
    }
}

#endif

XS_EUPXS(XS_Win32__API_LoadLibrary); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_LoadLibrary)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "name");
    {
	char *	name;
	HINSTANCE	RETVAL;
	dXSTARG;

	{SV * TmpPVSV = ST(0);
    name = (char *)SvPV_nolen(TmpPVSV);}
;
    RETVAL = LoadLibrary(name);
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Win32__API_GetProcAddress); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_GetProcAddress)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "library, name");
    {
	HINSTANCE	library;
	char *	name;
	long_ptr	RETVAL;
	dXSTARG;

	{SV * TmpIVSV = ST(0);
    library = (HINSTANCE)SvIV(TmpIVSV);}
;

	{SV * TmpPVSV = ST(1);
    name = (char *)SvPV_nolen(TmpPVSV);}
;
    RETVAL = (long_ptr) GetProcAddress(library, name);
	XSprePUSH; PUSHi(PTR2IV(RETVAL));
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Win32__API_FreeLibrary); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_FreeLibrary)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "library");
    {
	HINSTANCE	library;
	bool	RETVAL;

	{SV * TmpIVSV = ST(0);
    library = (HINSTANCE)SvIV(TmpIVSV);}
;
    RETVAL = FreeLibrary(library);
	ST(0) = boolSV(RETVAL);
    }
    XSRETURN(1);
}


XS_EUPXS(XS_Win32__API_ToUnicode); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_ToUnicode)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "string");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	LPCSTR	string;
    LPWSTR uString = NULL;
    int uStringLen;

	{SV * TmpPVSV = ST(0);
    string = (LPCSTR)SvPV_nolen(TmpPVSV);}
;
    uStringLen = MultiByteToWideChar(CP_ACP, 0, string, -1, uString, 0);
    if(uStringLen) {
        uString = (LPWSTR) safemalloc(uStringLen * 2);
        if(MultiByteToWideChar(CP_ACP, 0, string, -1, uString, uStringLen)) {
            XST_mPV(0, (char *) uString);
            safefree(uString);
            XSRETURN(1);
        } else {
            safefree(uString);
            XSRETURN_NO;
        }
    } else {
        XSRETURN_NO;
    }
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_FromUnicode); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_FromUnicode)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "uString");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	LPCWSTR	uString;
    LPSTR string = NULL;
    int stringLen;

	{SV * TmpPVSV = ST(0);
    uString = (LPCWSTR)SvPV_nolen(TmpPVSV);}
;
    stringLen = WideCharToMultiByte(CP_ACP, 0, uString, -1, string, 0, NULL, NULL);
    if(stringLen) {
        string = (LPSTR) safemalloc(stringLen);
        if(WideCharToMultiByte(CP_ACP, 0, uString, -1, string, stringLen, NULL, NULL)) {
            XST_mPV(0, (char *) string);
            safefree(string);
            XSRETURN(1);
        } else {
            safefree(string);
            XSRETURN_NO;
        }
    } else {
        XSRETURN_NO;
    }
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_PointerTo); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_PointerTo)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    SV * Target;
    if (items != 1)//must be CODE:
       croak_xs_usage(cv,  "Target");
    Target = *SP;
    SETs(sv_2mortal(newSViv((IV)SvPV_nolen(Target))));
    /* PUTBACK not needed, we got SP at +1 b/c of items check above, we return
      one item, so no need to assign SP to global SP */
    return;
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API_PointerAt); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_PointerAt)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "addr");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	long_ptr	addr;

	{SV * TmpPtrSV = ST(0);
    addr = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;
    XST_mPV(0, (char *) addr);
    XSRETURN(1);
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_IsBadReadPtr); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_IsBadReadPtr)
{
    dVAR; dXSARGS;
    dXSI32;
    if (items != 2)
       croak_xs_usage(cv,  "addr, len");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	long_ptr	addr;
	UV	len;
    SV * retsv;

	{SV * TmpPtrSV = ST(0);
    addr = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;

	{SV * TmpUVSV = ST(1);
    len = (UV)SvUV(TmpUVSV);}
;
    if(ix){
        if(IsBadStringPtr((void *)addr,len)) goto RET_YES;
        else goto RET_NO;
    }
    if(IsBadReadPtr((void *)addr,len)){
        RET_YES:
        retsv = &PL_sv_yes;
    }
    else{
        RET_NO:
        retsv = &PL_sv_no;
    }
    PUSHs(retsv);
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_ReadMemory); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_ReadMemory)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    SV * targ;
	long_ptr	addr;
	IV	len;
    if (items != 2)
       croak_xs_usage(cv,  "addr, len");
	{SV * TmpIVSV = POPs;
    len = (IV)SvIV(TmpIVSV);};
	{SV * TmpPtrSV = *SP;
    addr = INT2PTR(long_ptr,SvIV(TmpPtrSV));};
    targ = getTarg(aTHX);
    SETs(targ);
    PUTBACK;
    sv_setpvn_mg(targ, (char *) addr, len);
    return;
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API_WriteMemory); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_WriteMemory)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "destPtr, sourceSV, length");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
    SV ** dummy = PUTBACK; /* risky for breakage */
	long_ptr	destPtr;
	SV *	sourceSV = ST(1)
;
	size_t	length;
    char * sourcePV;
    STRLEN sourceLen;

	{SV * TmpPtrSV = ST(0);
    destPtr = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;

	{SV * TmpUVSV = ST(2);
    length = (size_t)SvUV(TmpUVSV);}
;
    sourcePV = SvPV(sourceSV, sourceLen);
	if(length > sourceLen)
        croak("%s, $length > length($source)", "Win32::API::WriteMemory");
    //they can't overlap so use faster memcpy
    memcpy((void *)destPtr, (void *)sourcePV, length);
    return;
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_MoveMemory); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_MoveMemory)
{
    dVAR; dXSARGS;
    if (items != 3)
       croak_xs_usage(cv,  "Destination, Source, Length");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
    SV ** dummy = PUTBACK; /* risky for breakage */
	long_ptr	Destination;
	long_ptr	Source;
	size_t	Length;

	{SV * TmpPtrSV = ST(0);
    Destination = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;

	{SV * TmpPtrSV = ST(1);
    Source = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;

	{SV * TmpUVSV = ST(2);
    Length = (size_t)SvUV(TmpUVSV);}
;
    MoveMemory((void *)Destination, (void *)Source, Length);
    return;
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_SafeReadWideCString); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_SafeReadWideCString)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "wstr");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	long_ptr	wstr;
    SV * targ;

	{SV * TmpPtrSV = ST(0);
    wstr = INT2PTR(long_ptr,SvIV(TmpPtrSV));}
;
    targ = getTarg(aTHX);
    PUSHs(targ);
    PUTBACK;
    if(wstr && ! IsBadStringPtrW((LPCWSTR)wstr, ~0)){
//WCTMB internally will do a dedicated len loop,
//not check NULL on the fly during the conversion, so cache it
//if a portable SEH is ever made, a rewrite combining SEH and wcslen
//is needed so CPU takes 1 instead of 2 passes through the string
        char * dest;
        size_t wlen_long = wcslen((LPCWSTR)wstr);
        int wlen;
        int len;
        BOOL use_default = FALSE;
        BOOL * use_default_ptr;    
        UINT CodePage;
        DWORD dwFlags;
        if(wlen_long > INT_MAX) croak("%s wide string overflowed >" STRINGIFY(INT_MAX), "Win32::API::SafeReadWideCString");
        wlen = (int) wlen_long;
        use_default_ptr = &use_default;
        CodePage = CP_ACP;
        dwFlags = WC_NO_BEST_FIT_CHARS;

        retry:
        len = WideCharToMultiByte(CodePage, dwFlags, (LPCWSTR)wstr, wlen, NULL, 0, NULL, NULL);
        dest = sv_grow(targ, (STRLEN)len+1); /*access vio on macro*/
        len = WideCharToMultiByte(CodePage, dwFlags, (LPCWSTR)wstr, wlen, dest, len, NULL, use_default_ptr);
        if (use_default) {
            SvUTF8_on(targ);
            /*this branch will never be taken again*/
            use_default = FALSE;
            use_default_ptr = NULL;
            CodePage = CP_UTF8;
            dwFlags = 0;
            goto retry;
        }
        if (len) {
            SvCUR_set(targ, len);
            SvPVX(targ)[len] = '\0';
        }
        SvPOK_on(targ); //zero length string on error/WCTMB len 0
    }
    //else stays undef
    SvSETMAGIC(targ);
    return;
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API_GetModuleFileName); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_GetModuleFileName)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "module");
    {
	HMODULE	module;
    SV * targ = getTarg(aTHX);
    DWORD nSize = MAX_PATH;
    WCHAR * lpFilename = (WCHAR *)_alloca(MAX_PATH * sizeof(WCHAR) /*MAXPATH*/);
    DWORD retSize;

	{SV * TmpIVSV = ST(0);
    module = (HMODULE)SvIV(TmpIVSV);}
;
    /* careful, complicated but efficient stack manipulation here */
    *SP = targ;
    PUTBACK;
    retry:
    retSize = GetModuleFileNameW(module, lpFilename, nSize);
    if(retSize){
        if(retSize == nSize){
    /*TLDR, a 65 KB path is highly unlikely, but still safe, and alloca is fine

    note, the original alloca alloc isn't freeded, so don't eat away at the C stack
    too aggressively, if something goes impossibly wrong with GetModuleFileNameW, a stack
    overflow will occur, on normal EXE's C stack is usually reserved for 1 MB,
    max unicode path possible is 32K characters, so 65 KB, we permanently alloced
    alot of pages, probably not, since Perl_peep/Perl_scalarvoid and friends
    are very recursive and like to blow alot of stack during BEGIN/compiling
    so at Perl Code runtime there actually are a couple pages free of C stack.*/
            lpFilename = (WCHAR *)_alloca((nSize += 256) * sizeof(WCHAR));
            goto retry;
        }
        w32sv_setwstr(aTHX_ targ, lpFilename, retSize+1);
    }
    /*else return undef, targ is already undef and pushed earier*/
    return;
    }
    XSRETURN_EMPTY;
}

#ifdef PERL_IMPLICIT_CONTEXT
#define XSubPPtmpAAAB 1


XS_EUPXS(XS_Win32__API__my_cxt_clone); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__my_cxt_clone)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    /* this sub might be returning everything it is passed */
    PUTBACK; /* some vars go out of scope now in machine code */
    {
        MY_CXT_CLONE; /* a redundant memcpy() on this line */
        /* get the SVs for this interp, not the parent interp*/
        initSharedKeys(aTHX_ &(MY_CXT));
    }
    return; /* dont execute another implied XSPP PUTBACK */
    }
    XSRETURN_EMPTY;
}

#endif
#ifdef ISDEV
#define XSubPPtmpAAAC 1


XS_EUPXS(XS_Win32__API__xxSetLastError); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__xxSetLastError)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "in");
    {
	IV	in;
    const union {
        void (__stdcall * normal) (DWORD);
        BOOL (__stdcall * special) (DWORD);
    } SLR_u = {SetLastError};
	IV	RETVAL;
	dXSTARG;

	{SV * TmpIVSV = ST(0);
    in = (IV)SvIV(TmpIVSV);}
;
    RETVAL = (IV) SLR_u.special((DWORD)in);
	XSprePUSH; PUSHi((IV)RETVAL);
    }
    XSRETURN(1);
}

#endif

XS_EUPXS(XS_Win32__API_SetMagicSV); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_SetMagicSV)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    SV * outside;
    SV * inside;
    if(items != 2)
        croak_xs_usage(cv, "outside, inside");
    inside = POPs;
    outside = POPs;
    PUTBACK;
    if(SvROK(outside) && SvROK(inside)) {
        outside = SvRV(outside);
        inside = SvRV(inside);
    }
    else{
        croak_xs_usage(cv, "outside, inside");
    }
    setMgSV(aTHX_ outside, inside);
    return;
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API_GetMagicSV); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API_GetMagicSV)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    SV * outside;
    SV * inside;
    if(items != 1)
    croak:
        croak_xs_usage(cv,  "reference");
    outside = *SP;
    if(!SvROK(outside))
        goto croak;
    outside = SvRV(outside);
    inside = getMgSV(aTHX_ outside);
    if(!inside)
        goto croak;
    *SP = sv_2mortal(newRV_inc(inside));
    /* no PUTBACK, got 1 item, returning 1 item */
    return;
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API__ImportXS); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__ImportXS)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
    char * subname;
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif
    assert(items == 2);
    /*if(items != 2)
        croak_xs_usage(cv,  "api, subname");*/
    {   SV * sv = POPs;
        subname = SvPVX(sv);    }
    {   SV * api = POPs;
        PUTBACK;
    {   CV * cv = newXS(subname, XS_Win32__API_ImportCall, file);
        XSANY.any_ptr = (APICONTROL *) SvPVX(SvRV(api));
        setMgSV(aTHX_ (SV*)cv, api);  }}
    return;
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API__Align); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Align)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "sv, boundary");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	sv = ST(0)
;
	size_t	boundary;
    char * buffer;
    size_t remainder;
    char * newbuffer;
    size_t orig_len;

	{SV * TmpUVSV = ST(1);
    boundary = (size_t)SvUV(TmpUVSV);}
;
    PUTBACK;
    if(((size_t)SvPVX(sv) % boundary) != 0){
        buffer = sv_grow(sv, SvCUR(sv)+boundary -1);
        if((remainder = (size_t) buffer % boundary) != 0){
            remainder = boundary - remainder;
            orig_len = SvCUR(sv);
            SvCUR_set(sv, orig_len+remainder);
            memmove((newbuffer= buffer+remainder), buffer, orig_len+1);//+1 for null char
            sv_chop(sv, newbuffer);
        }
    }
#ifndef NDEBUG
    if(((size_t) SvPVX(sv)% boundary) != 0 || *(SvPVX(sv) + SvCUR(sv)) != '\0')
        croak("bad alignment");
#endif
    return;
	PUTBACK;
	return;
    }
}

#ifdef WIN32_API_PROF
#define XSubPPtmpAAAD 1


XS_EUPXS(XS_Win32__API__DumpTimes); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__DumpTimes)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
    printf("dumptimes start %I64u loopprep %I64u loopstart %I64u Call_asm_b4 %I64u Call_asm_after %I64u rtn_time\n",
    start_loopprep.QuadPart, loopprep_loopstart.QuadPart, loopstart_Call_asm_b4.QuadPart, Call_asm_b4_Call_asm_after.QuadPart, Call_asm_after_return_time.QuadPart);
    }
    XSRETURN_EMPTY;
}

#endif
#ifdef WIN32_API_PROF
#define XSubPPtmpAAAE 1


XS_EUPXS(XS_Win32__API__ResetTimes); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__ResetTimes)
{
    dVAR; dXSARGS;
    if (items != 0)
       croak_xs_usage(cv,  "");
    {
    start_loopprep.QuadPart = 0,
    loopprep_loopstart.QuadPart = 0,
    loopstart_Call_asm_b4.QuadPart = 0,
    Call_asm_b4_Call_asm_after.QuadPart = 0,
    Call_asm_after_return_time.QuadPart = 0;
    }
    XSRETURN_EMPTY;
}

#endif
#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Win32__API); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Win32__API)
{
#if PERL_VERSION_LE(5, 21, 5)
    dVAR; dXSARGS;
#else
    dVAR; dXSBOOTARGSXSAPIVERCHK;
#endif
#if (PERL_REVISION == 5 && PERL_VERSION < 9)
    char* file = __FILE__;
#else
    const char* file = __FILE__;
#endif

    PERL_UNUSED_VAR(file);

    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(items); /* -W */
#if PERL_VERSION_LE(5, 21, 5)
    XS_VERSION_BOOTCHECK;
#  ifdef XS_APIVERSION_BOOTCHECK
    XS_APIVERSION_BOOTCHECK;
#  endif
#endif

#if XSubPPtmpAAAA
        newXS_deffile("Win32::API::UseMI64", XS_Win32__API_UseMI64);
#endif
        newXS_deffile("Win32::API::LoadLibrary", XS_Win32__API_LoadLibrary);
        newXS_deffile("Win32::API::GetProcAddress", XS_Win32__API_GetProcAddress);
        newXS_deffile("Win32::API::FreeLibrary", XS_Win32__API_FreeLibrary);
        newXS_deffile("Win32::API::ToUnicode", XS_Win32__API_ToUnicode);
        newXS_deffile("Win32::API::FromUnicode", XS_Win32__API_FromUnicode);
        newXS_deffile("Win32::API::PointerTo", XS_Win32__API_PointerTo);
        newXS_deffile("Win32::API::PointerAt", XS_Win32__API_PointerAt);
        cv = newXS_deffile("Win32::API::IsBadReadPtr", XS_Win32__API_IsBadReadPtr);
        XSANY.any_i32 = 0;
        cv = newXS_deffile("Win32::API::IsBadStringPtr", XS_Win32__API_IsBadReadPtr);
        XSANY.any_i32 = 1;
        newXS_deffile("Win32::API::ReadMemory", XS_Win32__API_ReadMemory);
        newXS_deffile("Win32::API::WriteMemory", XS_Win32__API_WriteMemory);
        newXS_deffile("Win32::API::MoveMemory", XS_Win32__API_MoveMemory);
        newXS_deffile("Win32::API::SafeReadWideCString", XS_Win32__API_SafeReadWideCString);
        newXS_deffile("Win32::API::GetModuleFileName", XS_Win32__API_GetModuleFileName);
#if XSubPPtmpAAAB
        newXS_deffile("Win32::API::_my_cxt_clone", XS_Win32__API__my_cxt_clone);
#endif
#if XSubPPtmpAAAC
        newXS_deffile("Win32::API::_xxSetLastError", XS_Win32__API__xxSetLastError);
#endif
        newXS_deffile("Win32::API::SetMagicSV", XS_Win32__API_SetMagicSV);
        newXS_deffile("Win32::API::GetMagicSV", XS_Win32__API_GetMagicSV);
        newXS_deffile("Win32::API::_ImportXS", XS_Win32__API__ImportXS);
        newXS_deffile("Win32::API::_Align", XS_Win32__API__Align);
#if XSubPPtmpAAAD
        newXS_deffile("Win32::API::_DumpTimes", XS_Win32__API__DumpTimes);
#endif
#if XSubPPtmpAAAE
        newXS_deffile("Win32::API::_ResetTimes", XS_Win32__API__ResetTimes);
#endif

    /* Initialisation Section */

    newXS("Win32::API::Call", XS_Win32__API_Call, file);
{
    SV * sentinal;
    SENTINAL_STRUCT sentinal_struct;
    LARGE_INTEGER counter;
#ifdef WIN32_API_DEBUG
    const char * const SDumpStr = "(XS)Win32::API::boot: APIPARAM layout, member %s, SzOf %u, offset %u\n";
#endif
    STATIC_ASSERT(sizeof(sentinal_struct) == 12); //8+2+2
    STATIC_ASSERT(sizeof(SENTINAL_STRUCT) == 2+2+8);    
#ifdef USEMI64
    STATIC_ASSERT(IVSIZE == 4);
#endif
#ifdef T_QUAD
    STATIC_ASSERT(sizeof(char *) == 4);
#endif
#ifdef WIN32_API_DEBUG
#define  DUMPMEM(type,name) printf(SDumpStr, #type " " #name, sizeof(((APIPARAM *)0)->name), offsetof(APIPARAM, name));
    DUMPMEM(int,t);
    DUMPMEM(LPBYTE,b);
    DUMPMEM(char,c);
    DUMPMEM(char*,p);
    DUMPMEM(long_ptr,l);
    DUMPMEM(float,f);
    DUMPMEM(double,d);
    printf("(XS)Win32::API::boot: APIPARAM total size=%u\n", sizeof(APIPARAM));
#undef DUMPMEM
#endif	
    //this is not secure against malicious overruns
    //QPC doesn't like unaligned pointers
    if(!QueryPerformanceCounter(&counter))
        croak("Win32::API::boot: internal error\n");
    sentinal_struct.counter = counter;
    sentinal_struct.null1 = L'\0';
    sentinal_struct.null2 = L'\0';
    {
        MY_CXT_INIT;
        sentinal = initSharedKeys(aTHX_ &(MY_CXT));
    }
    sv_setpvn(sentinal, (char*)&sentinal_struct, sizeof(sentinal_struct));
    {
    HV * stash = gv_stashpv("Win32::API", TRUE);
    //you can't ifdef inside a macro's parameters
#ifdef UNICODE
        newCONSTSUB(stash, "IsUnicode",&PL_sv_yes);
#else
        newCONSTSUB(stash, "IsUnicode",&PL_sv_no);
#endif
#ifdef __GNUC__
        newCONSTSUB(stash, "IsGCC",&PL_sv_yes);
#else
        newCONSTSUB(stash, "IsGCC",&PL_sv_no);
#endif
/*only used by tests with eval guard, dont create it on non-debugging to save memory*/
#ifdef WIN32_API_DEBUG
        newCONSTSUB(stash, "IsWIN32_API_DEBUG",&PL_sv_yes);
#endif
    {
    typedef struct {
        unsigned char len;
        unsigned char constval;
    } CONSTREG;
#pragma pack(push)
#pragma pack(push, 1)
    PORTALIGN(1)
    static const struct {
#define XMM(y)        CONSTREG cr_##y; char arr_##y [sizeof(#y)];
    XMM(T_VOID)
    XMM(T_NUMBER)
    XMM(T_POINTER)
    XMM(T_INTEGER)
    XMM(T_SHORT)
#ifndef _WIN64
    XMM(T_QUAD)
#endif
    XMM(T_CHAR)
    XMM(T_NUMCHAR)

    XMM(T_FLOAT)
    XMM(T_DOUBLE)
    XMM(T_STRUCTURE)

    XMM(T_POINTERPOINTER)
    XMM(T_CODE)

    XMM(T_FLAG_UNSIGNED)
    XMM(T_FLAG_NUMERIC)
#undef XMM
    } const_init = {
#define XMM(y)        { sizeof(#y)-1, y}, #y,
    XMM(T_VOID)
    XMM(T_NUMBER)
    XMM(T_POINTER)
    XMM(T_INTEGER)
    XMM(T_SHORT)
#ifndef _WIN64
    XMM(T_QUAD)
#endif
    XMM(T_CHAR)
    XMM(T_NUMCHAR)

    XMM(T_FLOAT)
    XMM(T_DOUBLE)
    XMM(T_STRUCTURE)

    XMM(T_POINTERPOINTER)
    XMM(T_CODE)

    XMM(T_FLAG_UNSIGNED)
    XMM(T_FLAG_NUMERIC)
#undef XMM
    };
#pragma pack(pop)
#pragma pack(pop)
    CONSTREG * entry = (CONSTREG *)&const_init;
    while((DWORD_PTR)entry < (DWORD_PTR)&const_init+sizeof(const_init)){
        newCONSTSUB(stash, (char *)((DWORD_PTR)entry+sizeof(CONSTREG)), newSVuv(entry->constval));
        /* +1 is jump past null */
        entry = (CONSTREG *)((DWORD_PTR) entry + sizeof(CONSTREG) + entry->len + 1);
    }
    }/* Perl constant init struct */
    }/* stash scope */
}

#if XSubPPtmpAAAA
#endif
#if XSubPPtmpAAAB
#endif
#if XSubPPtmpAAAC
#endif
#if XSubPPtmpAAAD
#endif
#if XSubPPtmpAAAE
#endif

    /* End of Initialisation Section */

#if PERL_VERSION_LE(5, 21, 5)
#  if PERL_VERSION_GE(5, 9, 0)
    if (PL_unitcheckav)
        call_list(PL_scopestack_ix, PL_unitcheckav);
#  endif
    XSRETURN_YES;
#else
    Perl_xs_boot_epilog(aTHX_ ax);
#endif
}

