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

#line 1 "Callback.xs"
/*
    # Win32::API::Callback - Perl Win32 API Import Facility
    #
    # Original Author: Aldo Calpini <dada@perl.it>
    # Rewrite Author: Daniel Dragan <bulk88@hotmail.com>
    # Maintainer: Cosimo Streppone <cosimo@cpan.org>
    #
    # Other Credits:
    # Changes for gcc/cygwin by Reini Urban <rurban@x-ray.at>  (code removed)
    #
    # $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"

//undo perl messing with stdio
//perl's stdio emulation layer is not OS thread safe
#define NO_XSLOCKS
#include "XSUB.h"
#define CROAK croak

#ifndef _WIN64
#define WIN32BIT
#define WIN32BITBOOL 1
#else
#define WIN32BITBOOL 0
#endif


#include "../API.h"

#define IMAGE_SNAP_BY_ORDINAL_CAST(x) IMAGE_SNAP_BY_ORDINAL((DWORD_PTR) x )
#define IMAGE_ORDINAL_CAST(x) IMAGE_ORDINAL((DWORD_PTR) x )

//older VSes dont have this flag
#ifndef HEAP_CREATE_ENABLE_EXECUTE
#define HEAP_CREATE_ENABLE_EXECUTE      0x00040000
#endif

HANDLE execHeap;

/*dont run CRT init code on MSVC, see note in API.xs*/
#ifdef _MSC_VER
BOOL WINAPI _DllMainCRTStartup(
#else
BOOL WINAPI DllMain(
#endif
    HINSTANCE hinstDLL,
    DWORD fdwReason,
    LPVOID lpReserved )
{
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
            DISABLE_T_L_CALLS;
            execHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE
                              | HEAP_GENERATE_EXCEPTIONS, 0, 0);
            if(!execHeap) return FALSE;
            break;
        case DLL_PROCESS_DETACH:
            return HeapDestroy(execHeap);
            break;
    }
    return TRUE;
}



/*
 * some Perl macros for backward compatibility
 */
#ifdef NT_BUILD_NUMBER
#define boolSV(b) ((b) ? &sv_yes : &sv_no)
#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_sv
#	define call_sv(name, flags) perl_call_sv(name, flags)
#endif

#ifdef WIN32BIT
typedef struct {
    unsigned short unwind_len;
    unsigned char F_Or_D;
    unsigned char unused;
} FuncRtnCxt;

#if 0
////the template used in the MakeCB for x86
unsigned __int64 CALLBACK CallbackTemplate2() {
    void (*PerlCallback)(SV *, void *, unsigned __int64 *, FuncRtnCxt *) = 0xC0DE0001;
    FuncRtnCxt FuncRtnCxtVar;
    unsigned __int64 retval;
    PerlCallback((SV *)0xC0DE0002, (void*)0xC0DE0003, &retval, &FuncRtnCxtVar);
    return retval;
}


typedef union {
    float f;
    double d;
} FDUNION;


////the template used in the MakeCB for x86
double CALLBACK CallbackTemplateD() {
    void (*PerlCallback)(SV *, void *, unsigned __int64 *, FuncRtnCxt *) = 0xC0DE0001;
    FuncRtnCxt FuncRtnCxtVar;
    FDUNION retval;
    PerlCallback((SV *)0xC0DE0002, (void*)0xC0DE0003, (unsigned __int64 *)&retval, &FuncRtnCxtVar);
    if(FuncRtnCxtVar.F_Or_D){
        return (double) retval.f;
    }
    else{
        return retval.d;        
    }
}
#endif //#if 0
#endif

////unused due to debugger callstack corruption
////alternate design was implemented
//#ifdef _WIN64
//
//#pragma optimize( "y", off)
//////the template used in the MakeCBx64
//void * CALLBACK CallbackTemplate64fin( void * a
//                                      //, void * b, void * c, void * d
//                                      , ...
//                                      ) {
//    void (*LPerlCallback)(SV *, void *, unsigned __int64 *, void *) =
//    ( void (*)(SV *, void *, unsigned __int64 *, void *)) 0xC0DE00FFFF000001;
//    __m128 arr [4];
//    __m128 retval;
//     arr[0].m128_u64[0] = 0xFFFF00000000FF10;
//     arr[0].m128_u64[1] = 0xFFFF00000000FF11;
//     arr[1].m128_u64[0] = 0xFFFF00000000FF20;
//     arr[1].m128_u64[1] = 0xFFFF00000000FF21;
//     arr[2].m128_u64[0] = 0xFFFF00000000FF30;
//     arr[2].m128_u64[1] = 0xFFFF00000000FF31;
//     arr[3].m128_u64[0] = 0xFFFF00000000FF40;
//     arr[3].m128_u64[1] = 0xFFFF00000000FF41;
//
//    LPerlCallback((SV *)0xC0DE00FFFF000002, (void*) arr, (unsigned __int64 *)&retval,
//                  (DWORD_PTR)&a);
//    return *(void **)&retval;
//}
//#pragma optimize( "", on )
//#endif

#ifdef WIN32BIT
typedef unsigned __int64 CBRETVAL; //8 bytes
#else
//using a M128 SSE variable casues VS to use aligned SSE movs, Perl's malloc
//(ithread mempool tracking included) on x64 apprently aligns to 8 bytes,
//not 16, then it crashes so DONT use a SSE type, even though it is
typedef struct {
    char arr[16];
} CHAR16ARR;
typedef CHAR16ARR CBRETVAL; //16 bytes
#endif

void PerlCallback(SV * obj, void * ebp, CBRETVAL * retval
#ifdef WIN32BIT               
                  ,FuncRtnCxt * rtncxt
#endif                  
                  ) {
    dTHX;
#if defined(USE_ITHREADS)
    {
        if(aTHX == NULL) {
            //due to NO_XSLOCKS, these are real CRT and not perl stdio hooks
            fprintf(stderr, "Win32::API::Callback (XS) no perl interp "
                   "in thread id %u, callback can not run\n", GetCurrentThreadId());
            //can't return safely without stack unwind count from perl on x86,
            //so exit thread is next safest thing, some/most libs will leak
            //from this
            ExitThread(0); // 0 means failure? IDK.
        }
    }
#endif
    {
	dSP;
    SV * retvalSV;
#ifdef WIN32BIT
    SV * unwindSV;
    SV * F_Or_DSV;
#endif
	ENTER;
    SAVETMPS;
	PUSHMARK(SP);
    EXTEND(SP, (WIN32BITBOOL?5:3));
    mPUSHs(newRV_inc((SV*)obj));
    mPUSHs(newSVuv((UV)ebp));
    retvalSV = sv_newmortal();
	PUSHs(retvalSV);
#ifdef WIN32BIT
    unwindSV = sv_newmortal();
    PUSHs(unwindSV);
    F_Or_DSV = sv_newmortal();
    PUSHs(F_Or_DSV);
#endif
	PUTBACK;
	call_pv("Win32::API::Callback::RunCB", G_VOID);
#ifdef WIN32BIT
    rtncxt->F_Or_D = (unsigned char) SvUV(F_Or_DSV);
    rtncxt->unwind_len = (unsigned short) SvUV(unwindSV);
#endif
    //pad out the buffer, uninit irrelavent
    *retval = *(CBRETVAL *)SvGROW(retvalSV, sizeof(CBRETVAL));
    FREETMPS;
	LEAVE;
    return;
    }
}

#ifdef _WIN64

//on entry R10 register must be a HV *
//, ... triggers copying to shadow space the 4 param registers on VS
//relying on compiler to not optimize away copying void *s b,c,d to shadow space
void CALLBACK Stage2CallbackX64( void * a
                                      //, void * b, void * c, void * d
                                      , ...
                                      ) {
    //CONTEXT is a macro in Perl, can't use it
    struct _CONTEXT cxt;
    CBRETVAL retval; //RtlCaptureContext is using a bomb to light a cigarette
    //a more efficient version is to write this in ASM, but that means GCC and
    //MASM versions, this func is pure C, "struct _CONTEXT cxt;" is 1232 bytes
    //long, pure hand written machine code in a string, like the jump trampoline
    //corrupts the callstack in VS 2008, RtlAddFunctionTable is ignored by VS
    //2008 but not WinDbg, but WinDbg is impossibly hard to use, if its not
    //in a DLL enumeratable by ToolHelp/Process Status API, VS won't see it
    //I tried a MMF of a .exe, the pages were formally backed by a copy of the
    //original .exe, VMMap verified, did a RtlAddFunctionTable, VS 2008 ignored
    //it, having Win32::API::Callback generate 1 function 1 time use DLLs from
    //a binary blob template in pure Perl is possible but insane
    RtlCaptureContext(&cxt); //null R10 in context is a flag to return
    if(!cxt.R10){//stack unwinding is not done
        return; //by callee on x64 so all funcs are vararg/cdecl safe
    }
    //don't assume there aren't any secret variables or secret alignment padding
    //, security cookie, etc, dont try to hard code &cxt-&a into a perl const sub
    //C compiler won't produce such a offset unless you run callbacktemplate live
    //calculating the offset in C watch window and hard coding it is going to
    //break in the future
    cxt.Rax = (unsigned __int64) &a;
    PerlCallback((SV *) cxt.R10, (void*) &cxt, &retval);
    cxt.Rax = *(unsigned __int64 *)&retval;
    cxt.Xmm0 = *(M128A *)&retval;
    cxt.R10 = (unsigned __int64)NULL; //trigger a return
    RtlRestoreContext(&cxt, NULL);//this jumps to the RtlCaptureContext line
    //unreachable
}
#endif


#if defined(USE_ITHREADS)
//Code here to make a inter thread refcount to deal with ithreads cloning
//to prevent a double free
    
int HeapBlockMgDup(pTHX_ MAGIC *mg, CLONE_PARAMS *param) {
    InterlockedIncrement((LONG *)mg->mg_ptr);
    return 1;
}
const static struct mgvtbl vtbl_HeapBlock = {
    NULL, NULL, NULL, NULL, NULL, NULL, HeapBlockMgDup, NULL, 
};
#endif

/* loops through the import table of a DLL, if the target import func is found
  it will be replaced, if OldFunc not null, old func ptr will be placed in OldFunc.
  On failure returns FALSE and error is in GLR. oldFunc is the only parameter
  which may be NULL. ImportFunctionName is treated as an ordinal if it is not
  POK*/
static BOOL PatchIAT(pTHX_ PIMAGE_DOS_HEADER dosHeader, SV * ImportDllName,
    SV * ImportFunctionName, void ** oldFunc, void * newFunc){
#define APPRVA2ABS(x) ((DWORD_PTR)dosHeader + (DWORD_PTR)(x))
    if( dosHeader
    && !IsBadReadPtr(dosHeader, sizeof(*dosHeader))
    && dosHeader->e_magic == IMAGE_DOS_SIGNATURE){
        PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)APPRVA2ABS(dosHeader->e_lfanew);
        if( ntHeader
        && !IsBadReadPtr(ntHeader, sizeof(*ntHeader))
        && ntHeader->Signature == IMAGE_NT_SIGNATURE
        && ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
        //not a OBJ file, bug below if some of the entrys are not present?
        && ntHeader->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER)
        && ntHeader->OptionalHeader.NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_IMPORT+1
        ){
            DWORD pDataDirImportRVA = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
            DWORD pDataDirImportSize = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
            PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)APPRVA2ABS(pDataDirImportRVA);
            if(pDataDirImportSize
               && pDataDirImportRVA
               && !IsBadReadPtr(importDescriptor, pDataDirImportSize)){
STRLEN DllNameLen;
char * DllNameStr = SvPV(ImportDllName, DllNameLen);
while (importDescriptor->Name != 0){
    const char * const TargetDllNameStr = (char *)APPRVA2ABS(importDescriptor->Name);
    const int TargetDllNameLen = lstrlenA(TargetDllNameStr); /*lstrlenA has SEH, strlen doesn't*/
#ifdef WIN32_API_DEBUG                                                              
    Perl_warn(aTHX_ "IATPatch::new saw app import dep dll name %s\n", TargetDllNameStr);
#endif
    if(TargetDllNameLen == 0) goto NO_MORE_LIBS;
    if(TargetDllNameLen == DllNameLen
        && strnicmp(TargetDllNameStr, DllNameStr, TargetDllNameLen) == 0
        && importDescriptor->OriginalFirstThunk
        && importDescriptor->FirstThunk
    ){
        PIMAGE_THUNK_DATA OriginalFirstThunk;
        void ** FirstThunk;
        STRLEN FunctionNameLen;
        char * FunctionNameStr;
        SvGETMAGIC(ImportFunctionName);
        if(SvPOK(ImportFunctionName)){
            FunctionNameStr = SvPV_nomg(ImportFunctionName, FunctionNameLen);
            if(IMAGE_SNAP_BY_ORDINAL_CAST(FunctionNameStr)) croak("IATPatch 3GB mode not supported");
        }
        else{ /*is an ordinal*/ 
            FunctionNameStr = (char *) (IMAGE_ORDINAL_FLAG | (DWORD_PTR)SvIV_nomg(ImportFunctionName));
        }/*XXX should we croak if not IOK but NOK or ROK?*/
        OriginalFirstThunk = (PIMAGE_THUNK_DATA)APPRVA2ABS(importDescriptor->OriginalFirstThunk);
        FirstThunk = (void**)APPRVA2ABS(importDescriptor->FirstThunk);
/*note only the first slice in the array is probed, they others should be valid if the 1st one is*/
        if(! IsBadReadPtr(OriginalFirstThunk, sizeof(IMAGE_THUNK_DATA))
           && ! IsBadReadPtr(FirstThunk, sizeof(void *))){
            while(OriginalFirstThunk->u1.ForwarderString != 0){
                /*ordinal status of want == ordinal status of have entry*/
                if(IMAGE_SNAP_BY_ORDINAL_CAST(FunctionNameStr) == IMAGE_SNAP_BY_ORDINAL(OriginalFirstThunk->u1.Ordinal)){
/*want ordinal*/    if(IMAGE_SNAP_BY_ORDINAL_CAST(FunctionNameStr)){
/*ordinals match*/      if(IMAGE_ORDINAL_CAST(FunctionNameStr)
                           == IMAGE_ORDINAL_CAST(OriginalFirstThunk->u1.Ordinal))
                            goto FOUND_IMPORT_ENTRY;
                    }/*end of want ordinal*/
/*want name*/       else{ 
PIMAGE_IMPORT_BY_NAME TargetImport = (PIMAGE_IMPORT_BY_NAME)APPRVA2ABS(OriginalFirstThunk->u1.AddressOfData);
char * TargetFunctionNameStr = TargetImport->Name;
int TargetFunctionNameLen = lstrlenA(TargetFunctionNameStr); /*lstrlenA has SEH, strlen doesn't*/
if(TargetFunctionNameLen == FunctionNameLen
   && memcmp(TargetFunctionNameStr, FunctionNameStr, TargetFunctionNameLen) == 0){
    FOUND_IMPORT_ENTRY:
    if(oldFunc) *oldFunc = *FirstThunk;
    if(IsBadWritePtr(FirstThunk, sizeof(void *))){ /*dont touch page flags unless mandatory*/
        DWORD newProtectFlag, oldProtectFlag;
        MEMORY_BASIC_INFORMATION mbi;    
        if(!VirtualQuery(FirstThunk, &mbi, sizeof(mbi) )) goto ERROR;
        newProtectFlag = mbi.Protect;
        newProtectFlag &= ~(PAGE_READONLY | PAGE_EXECUTE_READ);
        newProtectFlag |= PAGE_READWRITE;
        if (!VirtualProtect(FirstThunk, sizeof(void *), newProtectFlag, &oldProtectFlag)) goto ERROR;
        *FirstThunk = newFunc;    
        if (!VirtualProtect(FirstThunk, sizeof(void *), oldProtectFlag, &newProtectFlag)) goto ERROR;
        return TRUE;
    }
    *FirstThunk = newFunc;
    return TRUE;
}
                }/*end of want name*/
                }/*end of ordinal status test*/
#ifdef WIN32_API_DEBUG
/*this dont not print all import dll names and func names, only the ones seen
until the import we want to patch is found, if the import we want is not found,
then you see all of them
*/
                if(IMAGE_SNAP_BY_ORDINAL(OriginalFirstThunk->u1.Ordinal))
                    Perl_warn(aTHX_ "IATPatch::new saw app import dep ordinal %u\n",
                         IMAGE_ORDINAL_CAST(OriginalFirstThunk->u1.Ordinal));
                else{
                    PIMAGE_IMPORT_BY_NAME TargetImport = (PIMAGE_IMPORT_BY_NAME)APPRVA2ABS(OriginalFirstThunk->u1.AddressOfData);
                    char * TargetFunctionNameStr = TargetImport->Name;
                    int TargetFunctionNameLen = lstrlenA(TargetFunctionNameStr); /*lstrlenA has SEH, strlen doesn't*/
                    Perl_warn(aTHX_ "IATPatch::new saw app import dep func name %s\n"
                              , TargetFunctionNameLen? TargetFunctionNameStr : "is NULL" );
                }
#endif
                
                OriginalFirstThunk++;
                FirstThunk++;
            }
        }
        SetLastError(IMAGE_SNAP_BY_ORDINAL_CAST(FunctionNameStr) ? ERROR_INVALID_ORDINAL : ERROR_PROC_NOT_FOUND);
        goto ERROR;
    }
    importDescriptor++;
}
    NO_MORE_LIBS:
    SetLastError(ERROR_MOD_NOT_FOUND);
    goto ERROR;
}
}
}
    SetLastError(ERROR_BAD_EXE_FORMAT);
    ERROR:
    return FALSE;
#undef APPRVA2ABS
}

#line 424 "Callback.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

#line 568 "Callback.c"

XS_EUPXS(XS_Win32__API__Callback_PackedRVTarget); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback_PackedRVTarget)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "sv");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	sv = ST(0)
;
#line 439 "Callback.xs"
    mPUSHs(newSVpvn((char*)&(SvRV(sv)), sizeof(SV *)));
#line 583 "Callback.c"
	PUTBACK;
	return;
    }
}

#if IVSIZE == 4
#define XSubPPtmpAAAA 1


XS_EUPXS(XS_Win32__API__Callback_UseMI64); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback_UseMI64)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 446 "Callback.xs"
    SV * flag;
    HV * self;
    SV * old_flag;
#line 605 "Callback.c"
#line 450 "Callback.xs"
    if (items < 1 || items > 2)
       croak_xs_usage(cv,  "self [, FlagBool]");
    self = (HV*)ST(0);
	if (!(SvROK((SV*)self) && ((self = (HV*)SvRV((SV*)self)), SvTYPE((SV*)self) == SVt_PVHV)))
        Perl_croak(aTHX_ "%s: %s is not a hash reference",
			"Win32::API::Callback::UseMI64",
			"self");
    //dont create one if doesn't exist
    old_flag = (SV*)hv_fetch(self, "UseMI64", sizeof("UseMI64")-1, 0);
    if(old_flag) old_flag = *(SV **)old_flag;
    PUSHs(boolSV(sv_true(old_flag))); //old_flag might be NULL, ST(0) now gone

    if(items == 2){
        flag = boolSV(sv_true(ST(1)));
        hv_store(self, "UseMI64", sizeof("UseMI64")-1, flag, 0);
    }
#line 623 "Callback.c"
	PUTBACK;
	return;
    }
}

#endif

XS_EUPXS(XS_Win32__API__Callback_MakeParamArr); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback_MakeParamArr)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "self, arr");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	HV *	self;
	AV *	arr;
#line 490 "Callback.xs"
    AV * retarr = (AV*)sv_2mortal((SV*)newAV()); //croak possible
    int iTypes;
    AV * Types;
    I32 lenTypes;
#if (PERL_VERSION_LE(5, 8, 0))
    SV * unpacktypeSV = sv_newmortal();
#endif
#line 650 "Callback.c"

	STMT_START {
		SV* const xsub_tmp_sv = ST(0);
		SvGETMAGIC(xsub_tmp_sv);
		if (SvROK(xsub_tmp_sv) && SvTYPE(SvRV(xsub_tmp_sv)) == SVt_PVHV){
		    self = (HV*)SvRV(xsub_tmp_sv);
		}
		else{
		    Perl_croak_nocontext("%s: %s is not a HASH reference",
				"Win32::API::Callback::MakeParamArr",
				"self");
		}
	} STMT_END
;

	STMT_START {
		SV* const xsub_tmp_sv = ST(1);
		SvGETMAGIC(xsub_tmp_sv);
		if (SvROK(xsub_tmp_sv) && SvTYPE(SvRV(xsub_tmp_sv)) == SVt_PVAV){
		    arr = (AV*)SvRV(xsub_tmp_sv);
		}
		else{
		    Perl_croak_nocontext("%s: %s is not an ARRAY reference",
				"Win32::API::Callback::MakeParamArr",
				"arr");
		}
	} STMT_END
;
#line 498 "Callback.xs"
    //intypes array ref is always created in PM file
    Types = (AV*)SvRV(*hv_fetch(self, "intypes", sizeof("intypes")-1, 0));
    lenTypes = av_len(Types)+1;
    for(iTypes=0;iTypes < lenTypes;iTypes++){
        SV * typeSV = *av_fetch(Types, iTypes, 0);
        char type = *SvPVX(typeSV);
//both are never used on 64 bits
#ifdef T_QUAD
#define MK_PARAM_OP_8B 0x1
#endif
#ifdef USEMI64
#define MK_PARAM_OP_32BIT_QUAD 0x2
#endif
        char op = 0;
        SV * packedParamSV;
        char * packedParam;
        SV * unpackedParamSV;
        switch(type){
        case 's':
        case 'S':
            croak("Win32::API::Callback::MakeParamArr type letter \"S\" and"
                  " struct support not implemented");
            //in Perl this would be #push(@arr, MakeStruct($self, $i, $packedparam));
            //but ::Callback doesn't have C prototype type parsing
            //intypes arr is letters not C types
            break;
        case 'I': //type is already the correct unpack letter
        case 'i':
            break;
        case 'F':
            type = 'f';
        case 'f':
            break;
        case 'D':
            type = 'd';
        case 'd':
#if PTRSIZE == 4
                op = MK_PARAM_OP_8B;
#endif
            break;
        case 'N':
        case 'L':
#ifndef T_QUAD
        case 'Q':
#endif
#if PTRSIZE == 4
            type = 'L';
#else
            type = 'Q';
#endif
            break;
        case 'n':
        case 'l':
#ifndef T_QUAD
        case 'q':
#endif
#if PTRSIZE == 4
            type = 'l';
#else
            type = 'q';
#endif
            break;
#ifdef T_QUAD
        case 'q':
        case 'Q':
#ifdef USEMI64
            op = MK_PARAM_OP_32BIT_QUAD | MK_PARAM_OP_8B;
#else
            op = MK_PARAM_OP_8B;
#endif
            break;
#endif
        case 'P': //p/P are not documented and not implemented as a Callback ->
            type = 'p'; //return type, as "in" type probably works but this is 
        case 'p': //untested
            break;
        default:
            croak("Win32::API::Callback::MakeParamArr "
                  "\"in\" parameter %d type letter \"%c\" is unknown", iTypes+1, type);
        }

        packedParamSV = sv_2mortal(av_shift(arr));
#ifdef T_QUAD
        if(op & MK_PARAM_OP_8B)
            sv_catsv_nomg(packedParamSV, sv_2mortal(av_shift(arr)));
#endif
#ifdef USEMI64
        if((op & MK_PARAM_OP_32BIT_QUAD) == 0){
#endif
        packedParam = SvPVX(packedParamSV);
        if(type == 'p'){ //test if acc vio before a null is found, ret undef then
            if(IsBadStringPtr(packedParam, ~0)){
                unpackedParamSV = &PL_sv_undef;
            }
            else{
                unpackedParamSV = newSVpv(packedParam, 0);
            }
            goto HAVEUNPACKED;
        }
#if ! (PERL_VERSION_LE(5, 8, 0))
        PUTBACK;    
        unpackstring(&type, &type+1, packedParam, packedParam+SvCUR(packedParamSV), 0);
#else /* dont have unpackstring */
        PUSHMARK(SP);
        PUSHs(unpacktypeSV);
        PUSHs(packedParamSV);
        PUTBACK;
        sv_setpvn(unpacktypeSV,&type, 1);
        call_pv("Win32::API::Callback::_CallUnpack", G_SCALAR);
#endif
        SPAGAIN;
        unpackedParamSV = POPs;
#ifdef USEMI64
        }
        else{//have MK_PARAM_OP_32BIT_QUAD
            SV ** tmpsv = hv_fetch(self, "UseMI64", sizeof("UseMI64")-1, 0);
            if(tmpsv && sv_true(*tmpsv)){
                ENTER;
                PUSHMARK(SP); //stack extend not needed since we got 2 params
                //on the stack already from caller, so stack minimum 2 long
                PUSHs(packedParamSV); //currently mortal
                PUTBACK; //don't check return count, assume its 1
                call_pv(type == 'Q' ? "Math::Int64::native_to_uint64":
                        "Math::Int64::native_to_int64", G_SCALAR);
                SPAGAIN;
                unpackedParamSV = POPs; //this is also mortal
                LEAVE;
            }
            else{//pass through the 8 byte packed string
                unpackedParamSV = packedParamSV;
            }
        }
#endif //USEMI64
        SvREFCNT_inc_simple_NN(unpackedParamSV);//cancel the mortal
        HAVEUNPACKED: //used by 'p'/'P' for returning undef or a SVPV
        av_push(retarr, unpackedParamSV);
    }
    mPUSHs(newRV_inc((SV*)retarr)); //cancel the mortal, no X needed bc 2 in params
#ifdef T_QUAD
#undef MK_PARAM_OP_8B
#endif
#ifdef USEMI64
#undef MK_PARAM_OP_32BIT_QUAD
#endif
#line 824 "Callback.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API__Callback__HeapBlock_new); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__HeapBlock_new)
{
    dVAR; dXSARGS;
    if (items != 2)
       croak_xs_usage(cv,  "classSV, size");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	classSV = ST(0)
;
	UV	size;
#line 650 "Callback.xs"
    SV * newSVUVVar;
    char * block;
#if defined(USE_ITHREADS)
    MAGIC * mg;
    int alignRemainder;
#endif
#line 850 "Callback.c"

	{SV * TmpUVSV = ST(1);
    size = (UV)SvUV(TmpUVSV);}
;
#line 657 "Callback.xs"
    //Code here to make a inter thread refcount to deal with ithreads cloning
    //to prevent a double free
#if defined(USE_ITHREADS)
    alignRemainder = (size % sizeof(LONG)); //4%4 = 0, we are aligned
    size += sizeof(LONG) + (alignRemainder ? sizeof(LONG)-alignRemainder : 0);
#endif
    block = HeapAlloc(execHeap, 0, size);
    newSVUVVar = newSVuv((UV)block);
#if defined(USE_ITHREADS)
    mg = sv_magicext(newSVUVVar, NULL, PERL_MAGIC_ext,&vtbl_HeapBlock,NULL,0);
    mg->mg_flags |= MGf_DUP;
    mg->mg_ptr = block+size-sizeof(LONG);
    *((LONG *)mg->mg_ptr) = 1; //initial reference count
#endif
    mXPUSHs(sv_bless(newRV_noinc(newSVUVVar),
                    gv_stashsv(classSV,0)
                    )
           );
#line 874 "Callback.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API__Callback__HeapBlock_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__HeapBlock_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "ptr_obj");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	ptr_obj = ST(0)
;
#line 680 "Callback.xs"
    SV * SVUVVar;
#if defined(USE_ITHREADS)
    LONG refcnt;
    MAGIC * mg;
#endif
#line 898 "Callback.c"
#line 686 "Callback.xs"
    //Code here to make a inter thread refcount to deal with ithreads cloning
    //to prevent a double free
    SVUVVar = SvRV(ptr_obj);
#if defined(USE_ITHREADS)
    mg = mg_findext(SVUVVar, PERL_MAGIC_ext,&vtbl_HeapBlock);    
    refcnt = InterlockedDecrement((LONG *) mg->mg_ptr);
    if(refcnt == 0 ){ //if -1 or -2, means another thread will free it
#endif
    HeapFree(execHeap, 0, (LPVOID)SvUV(SVUVVar));
#if defined(USE_ITHREADS)
    }
#endif
#line 912 "Callback.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API__Callback__IATPatch_new); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__IATPatch_new)
{
    dVAR; dXSARGS;
    if (items != 5)
       croak_xs_usage(cv,  "classSV, callback, HookDll, ImportDllName, ImportFunctionName");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	classSV = ST(0)
;
	W32AC_T *	callback;
	SV *	HookDll = ST(2)
;
	SV *	ImportDllName = ST(3)
;
	SV *	ImportFunctionName = ST(4)
;
#line 709 "Callback.xs"
    PIMAGE_DOS_HEADER dosHeader;
    HV * returnHV;
    void * oldFunction;
    char * HookDllName;
#line 942 "Callback.c"

    {SV * TmpRV = ST(1);
	if (SvROK(TmpRV) && sv_derived_from(TmpRV, "Win32::API::Callback")) {
	    callback = (HV*)SvRV(TmpRV);
	}
	else
	    Perl_croak(aTHX_ "%s: %s is not of type %s",
			"Win32::API::Callback::IATPatch::new", "callback", "Win32::API::Callback");}
;
#line 714 "Callback.xs"
    SvGETMAGIC(HookDll);
    if(SvPOK(HookDll)){
        HookDllName = SvPV_nomg_nolen(HookDll);
        goto USE_GMH;
    }
    else if(SvIOK(HookDll)){
        dosHeader = (PIMAGE_DOS_HEADER) SvIV_nomg(HookDll);
        if(!dosHeader) goto BAD_USAGE;
    }
    else if(SvOK(HookDll)){ /*NVs RVs not valid*/
        BAD_USAGE:
        croak_xs_usage(cv,  "classSV, callback, HookDll, ImportDllName, ImportFunctionName");
    }
    else{ /* undef means patch the .exe that created the process*/
        HookDllName = NULL;
        USE_GMH:
        dosHeader = (PIMAGE_DOS_HEADER) GetModuleHandle(HookDllName);
        if(!dosHeader) goto ERROR;
    }
    if(!PatchIAT(aTHX_ dosHeader, ImportDllName, ImportFunctionName,
        &oldFunction, (void *)SvUVX(*hv_fetch(callback, "code", sizeof("code")-1, 0)))){
        ERROR:
        PUSHs(&PL_sv_undef);
        PUTBACK;
        return;    
    }
    returnHV = newHV();
    //save the hmod, not dll str name, other dlls with same name might have been
    //loaded in the meantime/sxs/etc
    hv_store(returnHV,  "HookDllHmod",          sizeof("HookDllHmod")-1,
                        newSVuv((UV)dosHeader), 0);
    hv_store(returnHV,  "OrigFunc",             sizeof("OrigFunc")-1,
                        newSVuv((UV)oldFunction) ,  0);
    hv_store(returnHV,  "ImportDllName",        sizeof("ImportDllName")-1,
                        newSVsv(ImportDllName), 0);
    hv_store(returnHV,  "ImportFunctionName",   sizeof("ImportFunctionName")-1,
                        newSVsv(ImportFunctionName), 0);
    hv_store(returnHV,  "callback",             sizeof("callback")-1,
                        newRV_inc((SV*)callback),    0);
    mPUSHs(sv_bless(newRV_noinc((SV*)returnHV),
                    gv_stashsv(classSV,0)
                    )
           );
#line 996 "Callback.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API__Callback__IATPatch_Unpatch); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__IATPatch_Unpatch)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    {
#line 761 "Callback.xs"
    I32 flagvar = 1; /*no param default is to restore*/
    SV * OrigFuncSV;
    void * OrigFunc;
    HV * self;
#line 1014 "Callback.c"
#line 766 "Callback.xs"
    if (items < 1 || items > 2)
       croak_xs_usage(cv, "self [, flag=true]");
    else if(items == 2){
        flagvar = sv_true(POPs);
    }
    {SV * TmpRV = POPs;
	if (SvROK(TmpRV) && sv_derived_from(TmpRV, "Win32::API::Callback::IATPatch")) {
	    self = (HV*)SvRV(TmpRV);
	}
	else
	    croak("%s: %s is not of type %s",
			"Win32::API::Callback::IATPatch::Unpatch",
            "self", "Win32::API::Callback::IATPatch");};
    OrigFuncSV = *hv_fetch(self, "OrigFunc", sizeof("OrigFunc")-1, 0);
    if(flagvar){
    if(OrigFunc = (void *)SvUVX(OrigFuncSV)){
        if(!PatchIAT(aTHX_
            (PIMAGE_DOS_HEADER)SvUVX(*hv_fetch(self, "HookDllHmod", sizeof("HookDllHmod")-1, 0)),
            *hv_fetch(self, "ImportDllName", sizeof("ImportDllName")-1, 0),
            *hv_fetch(self, "ImportFunctionName", sizeof("ImportFunctionName")-1, 0),
            NULL,       OrigFunc /*we don't collect the patch func ptr and
compare it to $self->{'callback'}->{'code'}, to see if something else patched
after us maybe we should????*/
        )){
            goto FAILED;
        }
        else goto SUCCESS_LABEL;
    }
    else SetLastError(ERROR_NO_MORE_ITEMS);
    }
    else{ //flag is false, never restore original function
    SUCCESS_LABEL:
        sv_setuv(OrigFuncSV, 0);
        PUSHs(&PL_sv_yes);
        PUTBACK;
        return;
    }
    FAILED:
    PUSHs(&PL_sv_undef);
    PUTBACK;
    return;
#line 1057 "Callback.c"
    }
    XSRETURN_EMPTY;
}


XS_EUPXS(XS_Win32__API__Callback__IATPatch_DESTROY); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__IATPatch_DESTROY)
{
    dVAR; dXSARGS;
    if (items != 1)
       croak_xs_usage(cv,  "self");
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
	SV *	self = ST(0)
;
#line 812 "Callback.xs"
    SV * retsv;
    DWORD error;
    DWORD error2;
#line 1078 "Callback.c"
#line 816 "Callback.xs"
    error = GetLastError(); //dont let DESTROY screw up a new
    PUSHMARK(SP);
    PUSHs(self);
    PUSHs(&PL_sv_yes);
    PUTBACK;
    XS_Win32__API__Callback__IATPatch_Unpatch(aTHX_ cv); /*the cv is wrong with this hack*/
    //call_pv("Win32::API::Callback::IATPatch::Unpatch", 0);
    retsv = POPs;
    if(!sv_true(retsv) /*ERROR_NO_MORE_ITEMS means it was already unpatched*/
       && (error2 = GetLastError()) != ERROR_NO_MORE_ITEMS){
        croak("%s: Failed to unpatch DLL, error number %u ",
              "Win32::API::Callback::IATPatch::DESTROY", error2);
    }
    SetLastError(error);
#line 1094 "Callback.c"
	PUTBACK;
	return;
    }
}


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

    {SV * TmpRV = ST(0);
	if (SvROK(TmpRV) && sv_derived_from(TmpRV, "Win32::API::Callback::IATPatch")) {
	    self = (HV*)SvRV(TmpRV);
	}
	else
	    Perl_croak(aTHX_ "%s: %s is not of type %s",
			"Win32::API::Callback::IATPatch::GetOriginalFunctionPtr", "self", "Win32::API::Callback::IATPatch");}
;
#line 840 "Callback.xs"
    PUSHs(sv_mortalcopy(*hv_fetch(self, "OrigFunc", sizeof("OrigFunc")-1, 0)));
#line 1122 "Callback.c"
	PUTBACK;
	return;
    }
}


XS_EUPXS(XS_Win32__API__Callback__IATPatch_CLONE_SKIP); /* prototype to pass -Wmissing-prototypes */
XS_EUPXS(XS_Win32__API__Callback__IATPatch_CLONE_SKIP)
{
    dVAR; dXSARGS;
    PERL_UNUSED_VAR(cv); /* -W */
    PERL_UNUSED_VAR(ax); /* -Wall */
    SP -= items;
    {
#line 846 "Callback.xs"
/* Prevent double unpatching from a fork. I dont think it makes sense to clone
  IATPatches, there is only one DLL per process. You can't have 2 different
  patches on it and have 2 different hooks expect to work based on the calling
  psuedo process. Well you could have a aTHX based dispatcher that will look up
  the correct weak ref ::Callback HV to use each time the PerlCallback() is
  called, but that is s alot of work for little gain. Currently the HV * of
  the ::Callback is hard coded into the ASM callback, and that HV * is interp
  specific.
*/
    PUSHs(&PL_sv_yes);
#line 1148 "Callback.c"
	PUTBACK;
	return;
    }
}

#ifdef __cplusplus
extern "C"
#endif
XS_EXTERNAL(boot_Win32__API__Callback); /* prototype to pass -Wmissing-prototypes */
XS_EXTERNAL(boot_Win32__API__Callback)
{
#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

        newXS_deffile("Win32::API::Callback::PackedRVTarget", XS_Win32__API__Callback_PackedRVTarget);
#if XSubPPtmpAAAA
        newXS_deffile("Win32::API::Callback::UseMI64", XS_Win32__API__Callback_UseMI64);
#endif
        newXS_deffile("Win32::API::Callback::MakeParamArr", XS_Win32__API__Callback_MakeParamArr);
        newXS_deffile("Win32::API::Callback::HeapBlock::new", XS_Win32__API__Callback__HeapBlock_new);
        newXS_deffile("Win32::API::Callback::HeapBlock::DESTROY", XS_Win32__API__Callback__HeapBlock_DESTROY);
        newXS_deffile("Win32::API::Callback::IATPatch::new", XS_Win32__API__Callback__IATPatch_new);
        newXS_deffile("Win32::API::Callback::IATPatch::Unpatch", XS_Win32__API__Callback__IATPatch_Unpatch);
        newXS_deffile("Win32::API::Callback::IATPatch::DESTROY", XS_Win32__API__Callback__IATPatch_DESTROY);
        newXS_deffile("Win32::API::Callback::IATPatch::GetOriginalFunctionPtr", XS_Win32__API__Callback__IATPatch_GetOriginalFunctionPtr);
        newXS_deffile("Win32::API::Callback::IATPatch::CLONE_SKIP", XS_Win32__API__Callback__IATPatch_CLONE_SKIP);

    /* Initialisation Section */

#line 419 "Callback.xs"
{
    SV * PtrHolder = get_sv("Win32::API::Callback::Stage2FuncPtrPkd", 1);
#ifdef _WIN64
    void * p = (void *)Stage2CallbackX64;
    HV *stash;
#else
    void * p = (void *)PerlCallback;
#endif
    sv_setpvn(PtrHolder, (char *)&p, sizeof(void *)); //gen a packed value
#ifdef _WIN64
    stash = gv_stashpv("Win32::API::Callback", TRUE);
    newCONSTSUB(stash, "CONTEXT_XMM0", newSViv(offsetof(struct  _CONTEXT, Xmm0)));
    newCONSTSUB(stash, "CONTEXT_RAX", newSViv(offsetof(struct  _CONTEXT, Rax)));
#endif
}

#if XSubPPtmpAAAA
#endif
#line 1216 "Callback.c"

    /* 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
}

