本文仅限零基础开发powerbuilder简单界面以及加载DLL函数,并不涉及powerbuilder的基础学习,也未涉及应用数据库,以入门的请越过此文。
好记性不如烂笔头,更不用说记性差了!写作本文就是为了把网上零散的内容结合实际开发整理一下,方便以后需要的时候随时可以参考。本次测试使用的是powerbuilder12.6版。
主要内容是使用c++开发一个DLL功能模块提供给powerbuilder开发使用。使用c++开发给pb使用的dll,对函数的导出需要指定为__stdcall并且需要写def模块定义文件。在这里主要测试基础参数类型在pb中的使用。
c++头文件pbdll.h
#pragma once
bool __stdcall setBool(bool v);
bool __stdcall getBool();
char __stdcall setChar(char v);
char __stdcall getChar();
short __stdcall setShort(short v);
short __stdcall getShort();
int __stdcall setInt(int v);
int __stdcall getInt();
long long __stdcall setLong(long long v);
long long __stdcall getLong();
float __stdcall setFloat(float v);
float __stdcall getFloat();
double __stdcall setDouble(double v);
double __stdcall getDouble();
const char* __stdcall setString(const char* v);
const char* __stdcall getString();
int __stdcall setImage(const unsigned char* v, int size);
const char* __stdcall getImage();
const char* __stdcall getNull();
c++源码文件pbdll.cpp
#include "pbdll.h"
#include <stdio.h>
#include <io.h>
#include <string>
template<class... _Args>
void LOG(const char* fmt, _Args&&... args)
{
FILE* fp = fopen("c:/pblog.txt", "at+");
if (fp)
{
fprintf(fp, fmt, std::forward<_Args>(args)...);
fclose(fp);
}
}
static bool bv = false;
bool __stdcall setBool(bool v)
{
LOG("bool=%d\n", v);
bool r = bv;
bv = v;
return r;
}
bool __stdcall getBool()
{
return bv;
}
static char cv = 'P';
char __stdcall setChar(char v)
{
LOG("char=%d\n", v);
char r = cv;
cv = v;
return r;
}
char __stdcall getChar()
{
return cv;
}
static short sv = 0x1234;
short __stdcall setShort(short v)
{
LOG("short=%d\n", v);
short r = sv;
sv = v;
return r;
}
short __stdcall getShort()
{
return sv;
}
static int iv = 0x12345678;
int __stdcall setInt(int v)
{
LOG("int=%d\n", v);
int r = iv;
iv = v;
return r;
}
int __stdcall getInt()
{
return iv;
}
static long long llv = 0x1234567812345678;
long long __stdcall setLong(long long v)
{
LOG("long=%lld\n", v);
long long r = llv;
llv = v;
return r;
}
long long __stdcall getLong()
{
return llv;
}
static float fv = 9.123;
float __stdcall setFloat(float v)
{
LOG("float=%f\n", v);
float r = fv;
fv = v;
return r;
}
float __stdcall getFloat()
{
return fv;
}
static double dv = 3.1415926;
double __stdcall setDouble(double v)
{
LOG("double=%lf\n", v);
double r = dv;
dv = v;
return r;
}
double __stdcall getDouble()
{
return dv;
}
static std::string str = "hello";
std::string r;
const char* __stdcall setString(const char* v)
{
LOG("string=%s\n", v);
r = str;
str = v;
return r.c_str();
}
const char* __stdcall getString()
{
return str.c_str();
}
int __stdcall setImage(const unsigned char* v, int size)
{
if (size)
{
FILE* fp = fopen("c:/pbt", "wb");
if (fp)
{
size_t r = fwrite(v, 1, size, fp);
fclose(fp);
return r;
}
return -1;
}
return 0;
}
const char* __stdcall getImage()
{
return "c:/pbt";
}
const char* __stdcall getNull()
{
return 0;
}
再新建一个pbdll.def文件
LIBRARY "pbdll"
DESCRIPTION 'pbdll Windows Dynamic Link Library'
EXPORTS
; Explicit exports can go here
setBool
getBool
setChar
getChar
setShort
getShort
setInt
getInt
setLong
getLong
setFloat
getFloat
setDouble
getDouble
setString
getString
setImage
getImage
getNull
编译生成一个pbdll.dll备用。
首先学习下Powerscript语言基础:https://blog.youkuaiyun.com/gyming/article/details/7883722#comments
然后了解下powerbuilder开发工具:https://wenku.baidu.com/view/a536f517dc36a32d7375a417866fb84ae45cc3ee.html
建立demo工程:
1.在你要创建工程的目录下新建该工程保存的文件夹。
2.new一个workspace,再new一个Target,选择Application。
3.new一个PB Object,选择window,设置好属性(随时都可以更改),Ctrl+S保存。
4.双击demo,实现demo的open事件,写上一句open(w_main)。
或者展开Events,双击open
导入dll中的函数,选择(Declare)——Global External Functions
其中getABC为dll中不存在的函数,ALIAS FOR "***;ANSI"表示字符串为ANSI编码,低版本的powerbuilder不需要加,具体根据dll的编码情况和powerbuilder的版本而定。
5.双击w_main(即新建的window)返回窗口,可以看到也有一个open事件,在这里可以做一些窗口初始化工作。切换到Layout标
签
如果需要在退出的时候做提示,可以切换到open标签,选择closequery事件并添加如下代码
6.拖控件,控件在菜单“Insert”——“Control”查看所有控件
在这里测试如下功能
对应的控件名称,其中Picture控件取消OriginalSize属性
bool类型 | st_bool | sle_bool | sle_bool2 |
8 bit整数 | st_char | sle_char | sle_char2 |
16 bit整数 | st_short | sle_short | sle_short2 |
32 bit整数 | st_int | sle_int | sle_int2 |
64 bit整数 | st_long | sle_long | sle_long2 |
单精度浮点数 | st_float | sle_float | sle_float2 |
双精度浮点数 | st_double | sle_double | sle_double2 |
char*字符串 | st_string | sle_string | sle_string2 |
文件 | p_1 | cb_1(按钮) | p_2 |
右边可以设置控件的属性、字体、显示位置大小等,左边可以批量调整控件对齐方式
7.双击test按钮,为clicked事件添加如下代码
if pb_getBool() then
pb_setBool(false)
else
pb_setBool(true)
end if
setChar(char(sle_char.text))
setShort(integer(sle_short.text))
setInt(long(sle_int.text))
setLong(longlong(sle_long.text))
setFloat(real(sle_float.text))
setDouble(double(sle_double.text))
setString(sle_string.text)
sle_bool2.text = string(pb_getBool())
sle_char2.text = string(getChar())
sle_short2.text = string(getShort())
sle_int2.text = string(getInt())
sle_long2.text = string(getLong())
sle_float2.text = string(getFloat())
sle_double2.text = string(getDouble())
sle_string2.text = getString()
if sle_char.text <> sle_char2.text then
sle_char2.backcolor = RGB(255, 0, 0)
else
sle_char2.backcolor = sle_char.backcolor
end if
if sle_short.text <> sle_short2.text then
sle_short2.backcolor = RGB(255, 0, 0)
else
sle_short2.backcolor = sle_short.backcolor
end if
if sle_int.text <> sle_int2.text then
sle_int2.backcolor = RGB(255, 0, 0)
else
sle_int2.backcolor = sle_int.backcolor
end if
if sle_long.text <> sle_long2.text then
sle_long2.backcolor = RGB(255, 0, 0)
else
sle_long2.backcolor = sle_long.backcolor
end if
if sle_float.text <> sle_float2.text then
sle_float2.backcolor = RGB(255, 0, 0)
else
sle_float2.backcolor = sle_float.backcolor
end if
if sle_double.text <> sle_double2.text then
sle_double2.backcolor = RGB(255, 0, 0)
else
sle_double2.backcolor = sle_double.backcolor
end if
if sle_string.text <> sle_string2.text then
sle_string2.backcolor = RGB(255, 0, 0)
else
sle_string2.backcolor = sle_string.backcolor
end if
string path = 'c:/'
string name = '1'
string fn, fne
fn = path + name
if FileExists(fn) then
fne = fn
else
fne = fn + ".bmp"
end if
if not FileExists(fne) then
fne = fn + ".jpg"
end if
if not FileExists(fne) then
fne = fn + ".png"
end if
int fp
blob fdata
if FileExists(fne) then
fp = FileOpen(fne, streammode!,read!,lockread!)
int rs
do
blob frd
rs = FileRead(fp, frd)
if rs > 0 then
fdata = fdata + frd
end if
loop while rs > 0
FileClose(fp);
long fsize
fsize = len(fdata)
if fsize > 0 then
p_1.setPicture(fdata)
setImage(fdata, fsize)
end if
else
p_1.picturename = ""
end if
string cfile
cfile = getImage()
if FileExists(cfile) then
fp = FileOpen(fne, streammode!,read!,lockread!)
FileReadEx(fp, fdata)
FileClose(fp);
if not isNull(fdata) then
p_2.setPicture(fdata)
end if
else
p_2.picturename = ""
end if
try
cfile = getNull()
if isNull(cfile) then
MessageBox('getNull','空')
elseif len(cfile) = 0 then
MessageBox('getNull','长度为0')
else
MessageBox('getNull',cfile)
end if
catch(RunTimeError e)
MessageBox('getNull',e.text)
end try
try
getABC()
catch(RunTimeError e1)
MessageBox('getABC',e1.text)
end try
8.切换到w_main——open事件,添加初始化控件代码
sle_bool.text = string(pb_getBool())
sle_char.text = string(getChar())
sle_short.text = string(getShort())
sle_int.text = string(getInt())
sle_long.text = string(getLong())
sle_float.text = string(getFloat())
sle_double.text = string(getDouble())
sle_string.text = getString()
9.点击Run运行
可以看到float类型有尾巴问题。修改各项后点击test按钮,会依次弹出如下消息框
证明不存在的函数会报runtime错误,最后的结果如图
进一步证明float类型的传递有问题。
总结:对于基本数据类型要注意c++的取值范围与pb的取值范围区别,对于浮点型数据最好转换成字符串进行传值,c++提供的dll不要使用指针类型(char*除外)。遇到pb里不懂的函数事件等首先查帮助文档,通过索引或搜索可以方便的找到要查的内容。
最后,生成exe文件:https://blog.youkuaiyun.com/tianwailaibin/article/details/8239583