在工作中遇到了一个python调用c的dll,最先尝试用ctype的windll和dll的方法去调用,都显示没有找到dll下的函数:
from ctypes import *
def load_dll():
return WinDLL('Api5040S')
def read_power():
print(load_dll().fnGetPowerValue)
if __name__ == '__main__':
read_power()
Traceback (most recent call last):
File "D:/Ptpythonworkspace/pythonProject2/Dome2.py", line 18, in <module>
read_power()
File "D:/Ptpythonworkspace/pythonProject2/Dome2.py", line 14, in read_power
print(load_dll().fnGetPowerValue)
File "D:\py37-32\lib\ctypes\__init__.py", line 369, in __getattr__
func = self.__getitem__(name)
File "D:\py37-32\lib\ctypes\__init__.py", line 374, in __getitem__
func = self._FuncPtr((name_or_ordinal, self))
AttributeError: function 'fnGetPowerValue' not found
百度了好久发现是因为:
客户也不愿意去更改dll,在绞尽脑汁之后,想了一个曲线救国的方法,用c#去调用c的dll,然后生成一个新的dll给python调用:
现在visual studio中写了一个调用c的dll的方法实验一下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Api5040S_NameSpace;
namespace ConsoleApp5
{
public class GetPowerValue
{
static void Main(string[] args)
{
Api5040S_NameSpace.Api5040S CallDll = new Api5040S_NameSpace.Api5040S();
string strErr = "";
float fPower = -45;
int iPort = Convert.ToInt32(1);
Console.Write(CallDll.fnGetPowerValue(1, "192.168.100.3", ref strErr, ref fPower, 2437, "192.168.100.254"));
Console.Write(fPower);
Console.ReadKey();
}
}
}
运行成功了:
接下来就需要把c#的调用生成一个dll,代码如下:ReadApi5040S.dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Api5040S_NameSpace;
namespace ReadApi5040S
{
public class Program
{
public static Tuple<string,float> GetPowerValue(int iPort, string strIp, ref string strErr, ref float fPower, int Frequency, string strRemoteIp = "192.168.100.254")
{
Api5040S_NameSpace.Api5040S CallDll = new Api5040S_NameSpace.Api5040S();
iPort = Convert.ToInt32(iPort);
strIp = strIp;
strErr = strErr;
fPower = -45;
Frequency = Frequency;
strRemoteIp = strRemoteIp;
int result = CallDll.fnGetPowerValue(iPort, strIp, ref strErr, ref fPower, Frequency, strRemoteIp = "192.168.100.254");
return Tuple.Create(strErr,fPower);
}
}
}
这样就能用python去调用里面封装的方法了。
接下来就是python调用c#的dll:
先安装pythonnet的安装包
pip install pythonnet
下面调用代码给上:
import clr
clr.AddReference("ReadApi5040S")
from ReadApi5040S import *
instance = Program()
def ReadPower():
iPort = 2
strIp = '192.168.100.3'
strErr = ''
fPower = 2
Frequency = 5500
strRemoteIp = '192.168.100.254'
return instance.GetPowerValue(iPort, strIp, strErr, fPower, Frequency, strRemoteIp)[2]
if __name__ == '__main__':
print(ReadPower())
运行结果:
D:\py37-32\python.exe D:/Ptpythonworkspace/pythonProject2/Demo.py
-90.0
Process finished with exit code 0
ok了,曲线救国成功了