ynkdir / py-win32more

Python bindings for Win32 API generated from win32metadata.
MIT License
112 stars 13 forks source link

Question: How to call function that uses different type than official document? #2

Closed byehack closed 1 year ago

byehack commented 1 year ago

Hi, I wanna migrate to win32more, here is my working code in ctypes:

LPWSTR = c_wchar_p
RPC_WSTR = LPWSTR
RPC_STATUS = LONG
P_RPC_WSTR = POINTER(RPC_WSTR)

RpcStringBindingComposeW = windll.rpcrt4.RpcStringBindingComposeW
RpcStringBindingComposeW.restype = RPC_STATUS
RpcStringBindingComposeW.argtypes = [RPC_WSTR, RPC_WSTR, RPC_WSTR, RPC_WSTR, RPC_WSTR, P_RPC_WSTR]

strBinding = RPC_WSTR()
rStatus = RpcStringBindingComposeW("0767a036-0d22-48aa-ba69-b619480f38cb", "ncalrpc", None, None, None, strBinding)

print(rStatus, strBinding.value)

I was thinking it should work in win32more too:

from Windows.Win32.System.Rpc import RpcStringBindingComposeW
from Windows.base import UInt16

strBinding = UInt16()
rStatus = RpcStringBindingComposeW("0767a036-0d22-48aa-ba69-b619480f38cb", "ncalrpc", None, None, None, strBinding)

but here is the error:

ArgumentError: argument 1: : expected LP_c_ushort instance instead of str
ynkdir commented 1 year ago

RpcStringBindingComposeW() is defined in Windows.Win32.winmd as following.

public unsafe static extern RPC_STATUS RpcStringBindingComposeW([Optional][In] ushort* ObjUuid, [Optional][In] ushort* ProtSeq, [Optional][In] ushort* NetworkAddr, [Optional][In] ushort* Endpoint, [Optional][In] ushort* Options, [Optional][Out] ushort** StringBinding);

And RPC_WSTR is not defined in the winmd.

It seems a problem of metadata.

I reported. https://github.com/microsoft/win32metadata/issues/1486

byehack commented 1 year ago

It seems a problem of metadata.

here is the implementation of RPC_WSTR in C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\shared\rpcdce.h:

#define __RPC_FAR
typedef _Null_terminated_ unsigned short __RPC_FAR * RPC_WSTR;

I think it defined correctly in winmd. but I don't know how to cast my input into that arguemnt types in win32more. (I'm not perfect in c/cpp so apologize if my answer is not make sense for you.)

ynkdir commented 1 year ago

You are right. I meant that we can cast python str to RPC_WSTR automatically if it was defined as type.

win32more uses ctypes as is. You can use ctypes.cast().

def str_to_RPC_WSTR(s: str) -> ctypes.POINTER(Window.base.UInt16):
    return ctypes.cast(Windows.base.c_wchar_p(s), ctypes.POINTER(Windows.base.UInt16))
byehack commented 1 year ago

Thanks, after few try worked, here is finall script:

from Windows.Win32.System.Rpc import RpcStringBindingComposeW
import Windows.base, ctypes

def str_to_RPC_WSTR(s: str) -> ctypes.POINTER(Windows.base.UInt16):
    return ctypes.cast(Windows.base.c_wchar_p(s), ctypes.POINTER(Windows.base.UInt16))

strBinding = ctypes.cast(Windows.base.c_wchar_p(), ctypes.POINTER(Windows.base.UInt16))
rStatus = RpcStringBindingComposeW(
    str_to_RPC_WSTR("0767a036-0d22-48aa-ba69-b619480f38cb"),
    str_to_RPC_WSTR("ncalrpc"),
    None,
    None,
    None,
    strBinding)
strBinding = ctypes.cast(strBinding, Windows.base.c_wchar_p)

print(rStatus, strBinding.value)

Is this progress can be easier?