在PB应用运行中要与C#的应用通信,经过查找网络资料及多位大佬的帮助,终于完成通信。现把自己的心得体会记录下来,供后学者少走弯路。
1.定义结构体,long类型为4个字节,故结构体的长度为12个字节,不能改变。
global type str_CopyDataStruct from structure
longdwdata
longcbdata
longlpdata
end type
2.申明本地外部应用函数
//查找指定显示标题的窗口句柄
FUNCTION ulong FindWindow(string lpClassName,string lpWindowName) LIBRARY "user32.dll" ALIAS FOR "FindWindowA"
FUNCTION ulong FindWindow(long lpClassName,string lpWindowName) LIBRARY "user32.dll" ALIAS FOR "FindWindowA"
//将源字符串COPY到新分配的内存块中并返回新分配的这个内存地址
Function long lstrcpy(ref string Destination, ref string Source) library "kernel32.dll"
//分配指定长度的内存块并返回该内存块的地址
Function long LocalAlloc(long Flags, long Bytes) library "kernel32.dll"
//释放指定内存地址的内存块,不要去释放由PB本身分配的那些内存块,只能释放由LocalAlloc分配的内存,否则系统会崩溃
Function long LocalFree(long MemHandle) library "kernel32.dll"
//将结构体数据COPY到指定内存地址的内存块中,size为结构体的长度
SUBROUTINE CopyMemory(long pDesc, ref str_copydatastruct pSrc, ulong size) LIBRARY 'kernel32' ALIAS FOR 'RtlMoveMemory'
//把指定内存地址的内存块COPY给相同的结构体,size为结构体的长度
SUBROUTINE CopyMemory(ref str_copydatastruct pDesc, long pSrc, ulong size) LIBRARY 'kernel32' ALIAS FOR 'RtlMoveMemory'
3.定义实体变量
//是WM_COPYDATA消息的消息号,当一个非PowerBuilder事件的Windows信息发生时触发。
//如果是跨进程通信(多个exe应用之间),则必须用此消息号,而不能用PB中的pbm_custom01等自定义事件,否则数据传递不成功。
CONSTANT Long WM_COPYDATA = 74
4.发送数据程序
string ls_Src, ls_Dst
long ll_ReceiveWinHandle, ll_Address, ll_SrcLen, ll_CopyDataPointer
str_CopyDataStruct lstr_cds
//查找接收数据的窗口句柄
ll_ReceiveWinHandle = FindWindow(0,'接收数据')
ls_Src = 'this is a test.'
ls_Dst = space(255)
ll_Address = lstrcpy(ls_Dst, ls_Src)
ll_SrcLen = len(ls_Src) + 1
lstr_cds.dwdata = 0//可以是您想传的任意long类型
lstr_cds.cbdata = ll_SrcLen//必须是所传字符串长度再加1,因为还会有一个结束标志
lstr_cds.lpdata = ll_Address//必须是字符串所在内存块的地址
ll_CopyDataPointer = LocalAlloc(0,12)
CopyMemory(ll_copyDataPointer,lstr_cds,12)
//将保存有结构体的内存块地址以消息的方式发送给目标窗口,事件ID为74,也可以使用API函数SendMessage来发送
//由于使用的是SendMessage(PB把SendMessage封装到Send函数中了),故会等待接收窗口返回结果。如果使用PostMessage则不会等待,只是判断发送是否成功
ll_rc = Send(ll_ReceiveWinHandle, WM_COPYDATA, 0, ll_copyDataPointer)
LocalFree(ll_copyDataPointer)
5.接收数据程序
//如果是跨进程通信(不管是PB应用与PB应用,还是PB应用与其它语言的应用),则必须使用PB窗口事件中的pbm_other事件
//如果不跨进程通信(即在同一个PB应用中),则可以使用PB窗口事件中的pbm_custom01等自定义事件
string ls_test
str_CopyDataStruct lstr_data
if Message.Number = WM_COPYDATA then
CopyMemory(lstr_data, lparam, 12)
ls_test = string(lstr_data.lpdata, "Address")//提取内存地址中的内容,格式符中必须是Address
end if
//处理完毕后的返回结果,可以重新定义。如果发送时使用的SendMessage则其一直在等这个结果
return 0
6.结束语
在PB中对内存的操作,一定不要去释放由PB本身分配的那些内存,要保持一个谁分配谁释放的原则。比如在接收数据的程序中,就不要去释放lparam指定的内存块,因为该内存块最终会由发送端去释放。
1.定义结构体,long类型为4个字节,故结构体的长度为12个字节,不能改变。
global type str_CopyDataStruct from structure
longdwdata
longcbdata
longlpdata
end type
2.申明本地外部应用函数
//查找指定显示标题的窗口句柄
FUNCTION ulong FindWindow(string lpClassName,string lpWindowName) LIBRARY "user32.dll" ALIAS FOR "FindWindowA"
FUNCTION ulong FindWindow(long lpClassName,string lpWindowName) LIBRARY "user32.dll" ALIAS FOR "FindWindowA"
//将源字符串COPY到新分配的内存块中并返回新分配的这个内存地址
Function long lstrcpy(ref string Destination, ref string Source) library "kernel32.dll"
//分配指定长度的内存块并返回该内存块的地址
Function long LocalAlloc(long Flags, long Bytes) library "kernel32.dll"
//释放指定内存地址的内存块,不要去释放由PB本身分配的那些内存块,只能释放由LocalAlloc分配的内存,否则系统会崩溃
Function long LocalFree(long MemHandle) library "kernel32.dll"
//将结构体数据COPY到指定内存地址的内存块中,size为结构体的长度
SUBROUTINE CopyMemory(long pDesc, ref str_copydatastruct pSrc, ulong size) LIBRARY 'kernel32' ALIAS FOR 'RtlMoveMemory'
//把指定内存地址的内存块COPY给相同的结构体,size为结构体的长度
SUBROUTINE CopyMemory(ref str_copydatastruct pDesc, long pSrc, ulong size) LIBRARY 'kernel32' ALIAS FOR 'RtlMoveMemory'
3.定义实体变量
//是WM_COPYDATA消息的消息号,当一个非PowerBuilder事件的Windows信息发生时触发。
//如果是跨进程通信(多个exe应用之间),则必须用此消息号,而不能用PB中的pbm_custom01等自定义事件,否则数据传递不成功。
CONSTANT Long WM_COPYDATA = 74
4.发送数据程序
string ls_Src, ls_Dst
long ll_ReceiveWinHandle, ll_Address, ll_SrcLen, ll_CopyDataPointer
str_CopyDataStruct lstr_cds
//查找接收数据的窗口句柄
ll_ReceiveWinHandle = FindWindow(0,'接收数据')
ls_Src = 'this is a test.'
ls_Dst = space(255)
ll_Address = lstrcpy(ls_Dst, ls_Src)
ll_SrcLen = len(ls_Src) + 1
lstr_cds.dwdata = 0//可以是您想传的任意long类型
lstr_cds.cbdata = ll_SrcLen//必须是所传字符串长度再加1,因为还会有一个结束标志
lstr_cds.lpdata = ll_Address//必须是字符串所在内存块的地址
ll_CopyDataPointer = LocalAlloc(0,12)
CopyMemory(ll_copyDataPointer,lstr_cds,12)
//将保存有结构体的内存块地址以消息的方式发送给目标窗口,事件ID为74,也可以使用API函数SendMessage来发送
//由于使用的是SendMessage(PB把SendMessage封装到Send函数中了),故会等待接收窗口返回结果。如果使用PostMessage则不会等待,只是判断发送是否成功
ll_rc = Send(ll_ReceiveWinHandle, WM_COPYDATA, 0, ll_copyDataPointer)
LocalFree(ll_copyDataPointer)
5.接收数据程序
//如果是跨进程通信(不管是PB应用与PB应用,还是PB应用与其它语言的应用),则必须使用PB窗口事件中的pbm_other事件
//如果不跨进程通信(即在同一个PB应用中),则可以使用PB窗口事件中的pbm_custom01等自定义事件
string ls_test
str_CopyDataStruct lstr_data
if Message.Number = WM_COPYDATA then
CopyMemory(lstr_data, lparam, 12)
ls_test = string(lstr_data.lpdata, "Address")//提取内存地址中的内容,格式符中必须是Address
end if
//处理完毕后的返回结果,可以重新定义。如果发送时使用的SendMessage则其一直在等这个结果
return 0
6.结束语
在PB中对内存的操作,一定不要去释放由PB本身分配的那些内存,要保持一个谁分配谁释放的原则。比如在接收数据的程序中,就不要去释放lparam指定的内存块,因为该内存块最终会由发送端去释放。