这个问题跟我出现的问题一样,我代码是这样写的:每次运行到Handle = QLIB_ConnectServer_LogicalPort(com),都会提示“实时错误49,DLL调用约定错误”。同是天涯沦落人啊,还是试了一天了,还是没有解决,也出来寻求帮助了 Dim Handle As Variant Dim result As Byte Private Declare Function QLIB_FTM_BT_Enable_Bluetooth Lib "QMSL_MSVC6R.dll" (ByVal Handle As Variant) As Byte Private Declare Function QLIB_ConnectServer_LogicalPort Lib "QMSL_MSVC6R.dll" (ByVal iLogicalPort As Long) As Variant com = Val(Trim(AT_COM)) Handle = QLIB_ConnectServer_LogicalPort(com) result = QLIB_FTM_BT_Enable_Bluetooth(Handle)
并不是只要是DLL,VB就能调用的。 DLL 有两种,一种是C专用的DLL,另一种是通用DLL。VB只能调用通用DLL。如果在C里面这样申明 double SEN_WaveToTemp(double fWave, int iChannel, int iSensor); 生成的就是C专用的DLL,只能被C语言调用。如果其它语言调用这样的DLL就是“DLL调用约定错误”通用DLL必须这样申明: double WINAPI SEN_WaveToTemp(double fWave, int iChannel, int iSensor);当然,尽管上述声明是可用的但是建议用WINAPI 声明的函数一律返回 int 值,指示函数是否执行成功。如果需要返回其它类型的值请在参数中返回。
//在VC中,通过结构体传参,最好使用指针,如: int SEN_ReadDSPData(stCHANNEL_LIST *pChannelData) { //... } '在VB中申明按地址传递 Private Declare Function SEN_ReadDSPData Lib "ReadData.dll" (pChannelData As Any) As Long'使用方法大致这样 Private Type stCHANNEL_LIST nChNum As Long '通道号。 nFreq As Long '该时间内采集的频率。 End TypePrivate Sub Command7_Click() Dim clBuffers() As stCHANNEL_LIST Dim rd As Long redim clBuffers(10) '... rd = SEN_ReadDSPData(clBuffers(0)) Text1.Text = rd End Sub
你可以尝试传递一个内寸句柄过去 Private Declare Function SEN_ReadDSPData Lib "ReadData.dll" (pChannelData As Long) As Long Dim Buffer As Long Dim rd As Long Buffer = GlobalAlloc(GMEM_ZEROINIT, 8*11) rd = SEN_ReadDSPData(Buffer) 'Buffer就是内存句柄 ... GlobalFree Buffer
Dim Handle As Variant
Dim result As Byte
Private Declare Function QLIB_FTM_BT_Enable_Bluetooth Lib "QMSL_MSVC6R.dll" (ByVal Handle As Variant) As Byte Private Declare Function QLIB_ConnectServer_LogicalPort Lib "QMSL_MSVC6R.dll" (ByVal iLogicalPort As Long) As Variant
com = Val(Trim(AT_COM))
Handle = QLIB_ConnectServer_LogicalPort(com)
result = QLIB_FTM_BT_Enable_Bluetooth(Handle)
http://topic.csdn.net/t/20020925/16/1052521.html
目的是要看到成功或失败的返回值,从中截取参数获取过程值,但是现在不知道VB语句怎么写才能成功
DLL 有两种,一种是C专用的DLL,另一种是通用DLL。VB只能调用通用DLL。如果在C里面这样申明 double SEN_WaveToTemp(double fWave, int iChannel, int iSensor);
生成的就是C专用的DLL,只能被C语言调用。如果其它语言调用这样的DLL就是“DLL调用约定错误”通用DLL必须这样申明:
double WINAPI SEN_WaveToTemp(double fWave, int iChannel, int iSensor);当然,尽管上述声明是可用的但是建议用WINAPI 声明的函数一律返回 int 值,指示函数是否执行成功。如果需要返回其它类型的值请在参数中返回。
我看你前面几个函数调用都成功了,觉得总应该是统一的格式。
让 VC 程序员检查一下。
//在VC中,通过结构体传参,最好使用指针,如:
int SEN_ReadDSPData(stCHANNEL_LIST *pChannelData)
{
//...
}
'在VB中申明按地址传递
Private Declare Function SEN_ReadDSPData Lib "ReadData.dll" (pChannelData As Any) As Long'使用方法大致这样
Private Type stCHANNEL_LIST
nChNum As Long '通道号。
nFreq As Long '该时间内采集的频率。
End TypePrivate Sub Command7_Click()
Dim clBuffers() As stCHANNEL_LIST
Dim rd As Long
redim clBuffers(10)
'...
rd = SEN_ReadDSPData(clBuffers(0))
Text1.Text = rd
End Sub
因为我没学过VC所以对C申明不理解,他这样写是否用VB调用不了呢,昨天跟对方联系他表示VB没试过,用.NET可以成功但是麻烦一些
谢谢,请问是否必须让对方修改VC.DLL里的申明才能执行以上VB申明和调用呢?
偶按照以上VB语句修改后执行,VB报内存出错,不能用written之类就关闭VB了
对方说,如果只调用返回函数值应该成功是0,失败非0... 如果要提取过程值,需要截取参数值进行解析,因为首要返回函数就提示失败提示必选参数,所以也不知道提取过程值的语句该怎么写了
Dim Buffer As Long
Dim rd As Long
Buffer = GlobalAlloc(GMEM_ZEROINIT, 8*11)
rd = SEN_ReadDSPData(Buffer)
'Buffer就是内存句柄
...
GlobalFree Buffer
{
//...
}
执行TEXT1.TEXT=SEN_ReadDSPData,却提示必选参数
是否Private Declare Function SEN_ReadDSPData Lib "ReadData.dll" _
(ByVal stCHANNEL_LIST As Long, _
ByVal pChannelData As Long, _
ByVal nSensorCount As Long, _
ByVal fWaveLengthVec As Long, _
ByVal fPowerDBVec As Long, _
ByVal nChNum As Long, _
ByVal nFreq As Long, _
ByVal tSensorListVec As Long) As Long
这个申明写错了呢?
还是因为 std::vector<float> fWaveLengthVec; 该通道的传感器波长序列。
std::vector<float> fPowerDBVec; 该通道的传感器功率序列。
std::vector<stCHANNEL_SENSOR_LIST> tSensorListVec; 传感器序列。
这个几个结构体参数VB完全不能调用呢?因为确定这点以后我可以找VC程序员商量,现在心里没底不确定,请大家解惑,谢谢。
如果是对方写的函数说明,绿色部分段落就是申明出现问题的函数
SEN_ReadDSPData
int SEN_ReadDSPData(stCHANNEL_LIST pChannelData[11])
参数:
[out] stCHANNEL_LIST pChannelData[11]:返回最多11通道100赫兹的波长数据。(0~10依次为1~11通道序列),数据结构说明详见下面。
结构体说明:
struct stCHANNEL_SENSOR_LIST {
int nSensorCount; 该通道的传感器数。
std::vector<float> fWaveLengthVec; 该通道的传感器波长序列。
std::vector<float> fPowerDBVec; 该通道的传感器功率序列。};
struct stCHANNEL_LIST {
int nChNum; 通道号。
int nFreq; 该时间内采集的频率。
std::vector<stCHANNEL_SENSOR_LIST> tSensorListVec; 传感器序列。};返回值:
0,表示读取成功;非0,读取失败。
如果在 VC++ 中没有声明为 int __stdcall SEN_ReadDSPData(stCHANNEL_LIST *pChannelData),在 VB 中就不可直接调用。VB 是默认标准调用的。解决方法:1 改 DLL。这个最简单。2 再写一个 DLL,作为标准调用接口。甚至可以把原 DLL 打包。3 最麻烦的,在 VB 中声明类来调用。我在原来回帖中曾有源码示例,搜搜。
谢谢,现在确认是对方的VC DLL不能直接被VB调用请问下前辈原来的回帖怎么搜索呢?我不太会使用论坛的功能。
std::vector<float> fWaveLengthVec; 该通道的传感器波长序列。
std::vector<float> fPowerDBVec; 该通道的传感器功率序列。
std::vector<stCHANNEL_SENSOR_LIST> tSensorListVec; 传感器序列。
有其他前辈说里面结构体参数std::vector 应该是 VC 特有类,不能在 VC 之外调用。请问这样确定目前VB没法调用这3个结构体参数吗,如果让对方程序员帮忙修改,这3个结构体参数也需要改吗?请各位前辈不吝赐教,谢谢。
目前比较简单的处理方式,是自己用 VC++ 写一个接口 DLL,其中调用原 DLL 。里面所有的函数都比照原来的写法,仅仅加上 __stdcall 关键字。为了区别,函数名可以前缀一些你自己的东西。函数内容就是调用原来的函数。生成 DLL 之后,你调自己的 DLL 就可以了。
谢谢前辈,这个方法确实比较简便,但是我从来没使用过C++,安装C++打开对整个界面毫无头绪,也不知道怎么写新DLL来调用原有DLL......昨天和对方程序员商量,他发了C++的调用源代码给我参考,但是关于SEN_ReadDSPData这个函数如何调用看得不是很明白,语句方面也不能理解并转换成VB语句 public partial class Form1 : Form
{
#region struc declare
/// <summary>
/// 原型定义
/// </summary>
const int MaxSensorCountPerChannel = 30;
const int MaxFreq = 150;
const int MaxChannelNum = 33;
[StructLayout(LayoutKind.Sequential)]
private struct SensorList
{
public int nSensorCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSensorCountPerChannel)]
public float[] fWaveLengthVec;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSensorCountPerChannel)]
public float[] fPowerDBVec;
}
[StructLayout(LayoutKind.Sequential)]
private struct PerChannel
{
public int nChNum;
public int nFreq;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxFreq)]
public SensorList[] tSensorListVec;
}
#endregion #region import dll
/// <summary>
/// 函数封装
/// </summary>
/// <returns></returns>
[DllImport("ReadData.dll")]
private static extern int SEN_Init(); [DllImport("ReadData.dll")]
private static extern void SEN_Close(); [DllImport("ReadData.dll")]
private static extern void SEN_ReadDSPData(IntPtr pp);
[DllImport("ReadData.dll")]
private static extern bool SEN_IsConnected(); [DllImport("ReadData.dll")]
private static extern int SEN_SendParaData();
#endregion #region dll function
private static int DllInit()
{
int rtn = -1;
try
{
rtn = SEN_Init();
}
catch
{
rtn = -2;
}
return rtn;
} private static int IsConnected()
{
int ret = 0;
if (!SEN_IsConnected())
{
ret = -1;
}
return ret;
} private static int SendParaData()
{
int ret = 0;
if (SEN_SendParaData() != 0)
{
ret = -2;
}
return ret;
} private static void DspClose()
{
SEN_Close();
}
/// <summary>
/// 获取数据
/// </summary>
/// <returns></returns>
private static PerChannel[] GetDataUseDll()
{
PerChannel[] channelList = new PerChannel[MaxChannelNum];
try
{
for (int i = 0; i < channelList.Length; i++)
{
channelList[i] = new PerChannel();
}
IntPtr[] ptArray = new IntPtr[1];
IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof (PerChannel))*MaxChannelNum);
Marshal.Copy(ptArray, 0, pt, 1); SEN_ReadDSPData( pt);
for (int i = 0; i < channelList.Length; i++)
{
channelList[i] =
(PerChannel)
Marshal.PtrToStructure((IntPtr) ((UInt32) pt + i*Marshal.SizeOf(typeof (PerChannel))),
typeof (PerChannel));
} Marshal.FreeHGlobal(pt);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
} return channelList; }
#endregion
http://support.microsoft.com/kb/153586/en-us3
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx