from __future__ import print_function
from ctypes import *
from ctypes.wintypes import DWORD, WIN32_FIND_DATAA, WIN32_FIND_DATAW, MAX_PATH
from comtypes import IUnknown, GUID, COMMETHOD, HRESULT, CoClass

# for GetPath
SLGP_SHORTPATH = 0x1
SLGP_UNCPRIORITY = 0x2
SLGP_RAWPATH = 0x4

# for SetShowCmd, GetShowCmd
##SW_SHOWNORMAL
##SW_SHOWMAXIMIZED
##SW_SHOWMINNOACTIVE


# for Resolve
##SLR_INVOKE_MSI
##SLR_NOLINKINFO
##SLR_NO_UI
##SLR_NOUPDATE
##SLR_NOSEARCH
##SLR_NOTRACK
##SLR_UPDATE

# fake these...
ITEMIDLIST = c_int
LPITEMIDLIST = LPCITEMIDLIST = POINTER(ITEMIDLIST)


class IShellLinkA(IUnknown):
    _iid_ = GUID("{000214EE-0000-0000-C000-000000000046}")
    _methods_ = [
        COMMETHOD(
            [],
            HRESULT,
            "GetPath",
            (["in", "out"], c_char_p, "pszFile"),
            (["in"], c_int, "cchMaxPath"),
            (["in", "out"], POINTER(WIN32_FIND_DATAA), "pfd"),
            (["in"], DWORD, "fFlags"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "GetIDList",
            (["retval", "out"], POINTER(LPITEMIDLIST), "ppidl"),
        ),
        COMMETHOD([], HRESULT, "SetIDList", (["in"], LPCITEMIDLIST, "pidl")),
        COMMETHOD(
            [],
            HRESULT,
            "GetDescription",
            (["in", "out"], c_char_p, "pszName"),
            (["in"], c_int, "cchMaxName"),
        ),
        COMMETHOD([], HRESULT, "SetDescription", (["in"], c_char_p, "pszName")),
        COMMETHOD(
            [],
            HRESULT,
            "GetWorkingDirectory",
            (["in", "out"], c_char_p, "pszDir"),
            (["in"], c_int, "cchMaxPath"),
        ),
        COMMETHOD([], HRESULT, "SetWorkingDirectory", (["in"], c_char_p, "pszDir")),
        COMMETHOD(
            [],
            HRESULT,
            "GetArguments",
            (["in", "out"], c_char_p, "pszArgs"),
            (["in"], c_int, "cchMaxPath"),
        ),
        COMMETHOD([], HRESULT, "SetArguments", (["in"], c_char_p, "pszArgs")),
        COMMETHOD(
            ["propget"],
            HRESULT,
            "Hotkey",
            (["retval", "out"], POINTER(c_short), "pwHotkey"),
        ),
        COMMETHOD(["propput"], HRESULT, "Hotkey", (["in"], c_short, "pwHotkey")),
        COMMETHOD(
            ["propget"],
            HRESULT,
            "ShowCmd",
            (["retval", "out"], POINTER(c_int), "piShowCmd"),
        ),
        COMMETHOD(["propput"], HRESULT, "ShowCmd", (["in"], c_int, "piShowCmd")),
        COMMETHOD(
            [],
            HRESULT,
            "GetIconLocation",
            (["in", "out"], c_char_p, "pszIconPath"),
            (["in"], c_int, "cchIconPath"),
            (["in", "out"], POINTER(c_int), "piIcon"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "SetIconLocation",
            (["in"], c_char_p, "pszIconPath"),
            (["in"], c_int, "iIcon"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "SetRelativePath",
            (["in"], c_char_p, "pszPathRel"),
            (["in"], DWORD, "dwReserved"),
        ),
        COMMETHOD(
            [], HRESULT, "Resolve", (["in"], c_int, "hwnd"), (["in"], DWORD, "fFlags")
        ),
        COMMETHOD([], HRESULT, "SetPath", (["in"], c_char_p, "pszFile")),
    ]

    def GetPath(self, flags=SLGP_SHORTPATH):
        buf = create_string_buffer(MAX_PATH)
        # We're not interested in WIN32_FIND_DATA
        self.__com_GetPath(buf, MAX_PATH, None, flags)
        return buf.value

    def GetDescription(self):
        buf = create_string_buffer(1024)
        self.__com_GetDescription(buf, 1024)
        return buf.value

    def GetWorkingDirectory(self):
        buf = create_string_buffer(MAX_PATH)
        self.__com_GetWorkingDirectory(buf, MAX_PATH)
        return buf.value

    def GetArguments(self):
        buf = create_string_buffer(1024)
        self.__com_GetArguments(buf, 1024)
        return buf.value

    def GetIconLocation(self):
        iIcon = c_int()
        buf = create_string_buffer(MAX_PATH)
        self.__com_GetIconLocation(buf, MAX_PATH, byref(iIcon))
        return buf.value, iIcon.value


class IShellLinkW(IUnknown):
    _iid_ = GUID("{000214F9-0000-0000-C000-000000000046}")
    _methods_ = [
        COMMETHOD(
            [],
            HRESULT,
            "GetPath",
            (["in", "out"], c_wchar_p, "pszFile"),
            (["in"], c_int, "cchMaxPath"),
            (["in", "out"], POINTER(WIN32_FIND_DATAW), "pfd"),
            (["in"], DWORD, "fFlags"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "GetIDList",
            (["retval", "out"], POINTER(LPITEMIDLIST), "ppidl"),
        ),
        COMMETHOD([], HRESULT, "SetIDList", (["in"], LPCITEMIDLIST, "pidl")),
        COMMETHOD(
            [],
            HRESULT,
            "GetDescription",
            (["in", "out"], c_wchar_p, "pszName"),
            (["in"], c_int, "cchMaxName"),
        ),
        COMMETHOD([], HRESULT, "SetDescription", (["in"], c_wchar_p, "pszName")),
        COMMETHOD(
            [],
            HRESULT,
            "GetWorkingDirectory",
            (["in", "out"], c_wchar_p, "pszDir"),
            (["in"], c_int, "cchMaxPath"),
        ),
        COMMETHOD([], HRESULT, "SetWorkingDirectory", (["in"], c_wchar_p, "pszDir")),
        COMMETHOD(
            [],
            HRESULT,
            "GetArguments",
            (["in", "out"], c_wchar_p, "pszArgs"),
            (["in"], c_int, "cchMaxPath"),
        ),
        COMMETHOD([], HRESULT, "SetArguments", (["in"], c_wchar_p, "pszArgs")),
        COMMETHOD(
            ["propget"],
            HRESULT,
            "Hotkey",
            (["retval", "out"], POINTER(c_short), "pwHotkey"),
        ),
        COMMETHOD(["propput"], HRESULT, "Hotkey", (["in"], c_short, "pwHotkey")),
        COMMETHOD(
            ["propget"],
            HRESULT,
            "ShowCmd",
            (["retval", "out"], POINTER(c_int), "piShowCmd"),
        ),
        COMMETHOD(["propput"], HRESULT, "ShowCmd", (["in"], c_int, "piShowCmd")),
        COMMETHOD(
            [],
            HRESULT,
            "GetIconLocation",
            (["in", "out"], c_wchar_p, "pszIconPath"),
            (["in"], c_int, "cchIconPath"),
            (["in", "out"], POINTER(c_int), "piIcon"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "SetIconLocation",
            (["in"], c_wchar_p, "pszIconPath"),
            (["in"], c_int, "iIcon"),
        ),
        COMMETHOD(
            [],
            HRESULT,
            "SetRelativePath",
            (["in"], c_wchar_p, "pszPathRel"),
            (["in"], DWORD, "dwReserved"),
        ),
        COMMETHOD(
            [], HRESULT, "Resolve", (["in"], c_int, "hwnd"), (["in"], DWORD, "fFlags")
        ),
        COMMETHOD([], HRESULT, "SetPath", (["in"], c_wchar_p, "pszFile")),
    ]

    def GetPath(self, flags=SLGP_SHORTPATH):
        buf = create_unicode_buffer(MAX_PATH)
        # We're not interested in WIN32_FIND_DATA
        self.__com_GetPath(buf, MAX_PATH, None, flags)
        return buf.value

    def GetDescription(self):
        buf = create_unicode_buffer(1024)
        self.__com_GetDescription(buf, 1024)
        return buf.value

    def GetWorkingDirectory(self):
        buf = create_unicode_buffer(MAX_PATH)
        self.__com_GetWorkingDirectory(buf, MAX_PATH)
        return buf.value

    def GetArguments(self):
        buf = create_unicode_buffer(1024)
        self.__com_GetArguments(buf, 1024)
        return buf.value

    def GetIconLocation(self):
        iIcon = c_int()
        buf = create_unicode_buffer(MAX_PATH)
        self.__com_GetIconLocation(buf, MAX_PATH, byref(iIcon))
        return buf.value, iIcon.value


class ShellLink(CoClass):
    """ShellLink class"""

    _reg_clsid_ = GUID("{00021401-0000-0000-C000-000000000046}")
    _idlflags_ = []
    _com_interfaces_ = [IShellLinkW, IShellLinkA]


if __name__ == "__main__":

    import sys
    import comtypes
    from comtypes.client import CreateObject
    from comtypes.persist import IPersistFile

    shortcut = CreateObject(ShellLink)
    print(shortcut)
    ##help(shortcut)

    shortcut.SetPath(sys.executable)

    shortcut.SetDescription("Python %s" % sys.version)
    shortcut.SetIconLocation(sys.executable, 1)

    print(shortcut.GetPath(2))
    print(shortcut.GetIconLocation())

    pf = shortcut.QueryInterface(IPersistFile)
    pf.Save("foo.lnk", True)
    print(pf.GetCurFile())
