/***********************************************************************

_sysloader.cpp -- a helper module for loading the
PyWin32 "system" modules win32types and pythoncom.

Note that this module does (and must) *NOT* link to win32typesXX.dll

See win32types.py for more information.

********************************************************************/
#include "windows.h"
// Windows rpc.h defines "small" as "char" and Python 3.x's accu.h uses
// "small" as a structure element causing compilation errors :(
#ifdef small
#undef small
#endif
#include "Python.h"

// GetModuleHandle and GetModuleFilename rolled into 1
static PyObject *PyGetModuleFilename(PyObject *self, PyObject *args)
{
// For py3k, will be built with UNICODE defined
#ifdef UNICODE
    static char *fmt = "u";
#else
    static char *fmt = "s";
#endif

    TCHAR *modName = NULL;
    if (!PyArg_ParseTuple(args, fmt, &modName))
        return NULL;
    HINSTANCE hinst = GetModuleHandle(modName);
    if (hinst == NULL)
    {
        Py_INCREF(Py_None);
        return Py_None;
    }
    TCHAR buf[_MAX_PATH];
    if (GetModuleFileName(hinst, buf, sizeof(buf) / sizeof(buf[0])) == 0)
    {
        Py_INCREF(Py_None);
        return Py_None;
    }
#ifdef UNICODE
    return PyUnicode_FromUnicode(buf, wcslen(buf));
#else
    return PyString_FromString(buf);
#endif
}

static PyObject *PyLoadModule(PyObject *self, PyObject *args)
{
#ifdef UNICODE
    static char *fmt = "u";
#else
    static char *fmt = "s";
#endif
    TCHAR *modName = NULL;
    if (!PyArg_ParseTuple(args, fmt, &modName))
        return NULL;
    HINSTANCE hinst = LoadLibrary(modName);

    if (hinst == NULL)
    {
        Py_INCREF(Py_None);
        return Py_None;
    }
    TCHAR buf[_MAX_PATH];
    if (GetModuleFileName(hinst, buf, sizeof(buf) / sizeof(buf[0])) == 0)
    {
        Py_INCREF(Py_None);
        return Py_None;
    }
#ifdef UNICODE
    return PyUnicode_FromUnicode(buf, wcslen(buf));
#else
    return PyString_FromString(buf);
#endif
}

static struct PyMethodDef functions[] = {
    {"GetModuleFilename", PyGetModuleFilename, 1},
    {"LoadModule", PyLoadModule, 1},
    {NULL}};

extern "C" __declspec(dllexport)
#if (PY_VERSION_HEX < 0x03000000)
    void init_sysloader(void)
{
    PyObject *module = Py_InitModule("_sysloader", functions);
}
#else
    PyObject *PyInit__sysloader(void)
{
    static PyModuleDef _sysloader_def = {
        PyModuleDef_HEAD_INIT,
        "_sysloader",
        "Exists only to load Pywin32 system modules",
        -1,
        functions};
    PyObject *module = PyModule_Create(&_sysloader_def);
    return module;
}
#endif
