用PBNI实现软件注册授权控制(二)

    即然PB程序采用调用DLL文件的方式来进行软件注册授权控制,很容易被绕开,那么该如何解决这一问题呢?
      从PB9开始,增加了PBNI功能,可以直接采用VC来编写可视和不可视的组件给PB的应用程序调用,以实现PB应用功能的扩展.采用这种技术架构,可以非常方便的把原来的VC中的功能,封装为PB的可视对象或不可视对象,给PB的应用程序使用,而不需要在程序中定义各种API函数.而且由于PBNI编译后的PBD文件,并不是使用PB的代码指令,用pbkiller和Shudepb都无法对期进行反编译,可以有效的保护软件系统核心部分代码的安全.
      下面,我们采用VC6来开发一个PBNI组件,用于封装上一篇文件中所实现的CheckKey和Add函数功能.(如果是PB9,则建议采用VC6作为开发环境,如果是PB10以上版本,则建议采用VS2003作为开发环境.)
 

配置开发环境

      首先,按照帮助文件的说明,配置VC6的开发环境,以便使用PBNI的应用向导,以及向开发环境增加PBNI的头文件和库文件的目录.
       1.把C:/Program Files/Sybase/PowerBuilder 9.0/SDK/PBNI/wizards/pbext.awx文件拷到C:/Program Files/Microsoft Visual Studio/COMMON/MSDev98/Bin/IDE目录,以便在VC6中可以使用PBNI应用程序向导.
      2.打开VC6,选择工具---选择---目录,增加以下选项.
      C:/Program Files/Sybase/PowerBuilder 9.0/SDK/PBNI/include
      C:/Program Files/Sybase/PowerBuilder 9.0/SDK/PBNI/Lib

新建一个PBNI工程

      1.文件---新建---工程,选择PBNI Extension App Wizard,输入工程名称,选择工程的保存路径,按确定.

 

      2.输入对象名称,n_cst_service,由于VC6的向导只能增加不可视对象,所以该对象最好生成的是不可视对象组件.

      3.按完成,向导出自动生成PBNI所需要的各种全局函数,并增加了n_cst_Service这个不可视对象的定义,以及相对应的VC类对象.向导会为n_cst_Service增加SampleMethod1和SampleMethod2两个函数,这两个函数没什么意义,需要把它改成需要的CheckKey的Add函数.

实现对象功能

       1.打开PBX_GetDescription函数,定义生成PB对象的描述定义.向导生成的n_cst_service对象的代码如下:


PBXEXPORT LPCTSTR PBXCALL PBX_GetDescription()
{
  
static const TCHAR class_descs[] = 
  {
    
"class n_cst_service from nonvisualobject/n"
    
// TODO : Add in your PBNI class functions here.
    "function long SampleMethod1()/n"
    
"function long SampleMethod2()/n"
    
"end class/n" 
  };

  
return class_descs;
}

 

 把SmpleMethod1和SampleMethod2删除掉,并增加CheckKey和Add函数的定义,n_cst_service的描述定义最后为:

 
PBXEXPORT LPCTSTR PBXCALL PBX_GetDescription()
{
  
static const TCHAR class_descs[] = 
  {
    
"class n_cst_service from nonvisualobject/n"
    
// TODO : Add in your PBNI class functions here.
    "function boolean CheckKey(string key)/n"
    
"function int Add(int a , int b )/n"
    
"end class/n" 
  };

  
return class_descs;
}

      2.打开n_cst_service.h文件,修改n_cst_service对应的vc类的定义,删除SampleMethod1和SampleMethod2函数的定义,并增加ChcekKey和Add函数的定义,最后代码如下


class Cn_cst_service : public IPBX_NonVisualObject
{
  
enum MethodIDs
  {
    mid_CheckKey 
= 0,
    mid_Add 
= 1
  };
  
virtual void Destroy();

public:
  Cn_cst_service();
  Cn_cst_service(IPB_Session
* pIPB_Session, pbobject pbobj);
  
~Cn_cst_service();

  
// IPBX_UserObject methods.
  PBXRESULT Invoke
  (
    IPB_Session    
*session, 
    pbobject    obj, 
    pbmethodID    mid,
    PBCallInfo    
*ci
  );

 
protected:
  PBXRESULT CheckKey
  (
    IPB_Session    
*session, 
    pbobject    obj, 
    PBCallInfo    
*ci
  );

  PBXRESULT Add
  (
    IPB_Session    
*session, 
    pbobject    obj, 
    PBCallInfo    
*ci
  );

      3.打开n_cst_service.cpp文件,同样删除向导生成的函数,并增加CheckKey和Add函数的功能,最后生成的代码如下:
     



// IPBX_UserObject method.
PBXRESULT Cn_cst_service::Invoke
(
  IPB_Session    
*session, 
  pbobject    obj, 
  pbmethodID    mid,
  PBCallInfo    
*ci
)
{
  PBXRESULT pbrRet 
= PBX_E_INVOKE_FAILURE; // First assume function associated with "mid" is not found.

  
if (mid == mid_CheckKey)
  {
    pbrRet 
= (PBXRESULT)CheckKey
    (
      (IPB_Session
*)session, 
      (pbobject)obj, 
      (PBCallInfo
*)ci
    );
  }

  
if (mid == mid_Add)
  {
    pbrRet 
= (PBXRESULT)Add
    (
      (IPB_Session
*)session, 
      (pbobject)obj, 
      (PBCallInfo
*)ci
    );
  }

  
return pbrRet;
}




// PB callable Cn_cst_service method.
PBXRESULT Cn_cst_service::CheckKey
(
  IPB_Session    
*session, 
  pbobject    obj, 
  PBCallInfo    
*ci
)
{

  PBXRESULT pbrRet 
= PBX_OK;
  LPCSTR key 
=session->GetString( ci->pArgs->GetAt(0)->GetString() );  //取传入的参数
  if(strcmp(key,"12345678")==0)
  {
       ci 
-> returnValue -> SetBool(true);  //设置返回值
  }
  
else
  {
      ci 
-> returnValue -> SetBool(false);
  }

  
return pbrRet;
}





// PB callable Cn_cst_service method.
PBXRESULT Cn_cst_service::Add
(
  IPB_Session    
*session, 
  pbobject    obj, 
  PBCallInfo    
*ci
)
{
  PBXRESULT pbrRet 
= PBX_OK;

  
int a, b, result;
  a 
=(int)ci->pArgs->GetAt(0)->GetInt();
  b 
=(int)ci->pArgs->GetAt(1)->GetInt();
  result 
= a+b; 
  ci 
-> returnValue -> SetInt(result);

  
return pbrRet;
}

      4.编译程序,生成pbx文件.
      5.用pbx2pbd90程序,生成pb应用程序使用的pbd文件.       

        pbx2pbd90  {dir}/PBNI_Test.pbd  {dir}/PBNI_Test.PBX

引用程序

      1.把PBNI_Test.PBX和PBNI_Test.PBD拷贝到pb程序应用的目录下,用pb9打开应用程序,,在程序的库文件列表中增中上面生成的PBD文件.
      2.打开w_main窗口,CheckKey按钮的代码更改为:


Code
n_cst_service  n_service
n_service 
= Create n_cst_service 

IF n_service.CheckKey(
"12345678") Then
    MessageBox(
"提示1","注册码12345678正确!")
ELSE
    MessageBox(
"提示1","注册码12345678错误!")
END IF

IF n_service.CheckKey(
"abcdefg") Then
    MessageBox(
"提示2","注册码abcdefg正确!")
ELSE
    MessageBox(
"提示2","注册码abcdefg错误!")
END IF

Destroy n_service 

      Add按钮的代码更改为:

n_cst_service  n_service
n_service 
=  Create n_cst_service 
MessageBox(
' Add计算 ' , " 100+30= " + string (n_service.Add( 100 , 30 )))
Destroy n_service 

      3.运行程序,点击CheckKey按钮,弹出下面两个窗口


      点击Add按钮,弹出下面窗口.

    
        4.使用pbkiller打开上面生成的pbd文件,显示错误信息,不能被反编译.

 

后注

      使用PBNI可以防止代码被pbkiller和shudepb反编译,也可以防止直接采用dll的方式,被直接绕开的情况,相对要安全一点.但这种安全也是相对的,所以一般还需要在程序增加对这个pbd文件进行验证,如根据文件的MD5值,确定该文件没有被修改或被替换.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
服务端(jsxserver),采用c++ + iocp + pbni + zlib编写而成,支持PB长连结(提供pb客户端demo),支持http get post调用,pbni调用pbcall里的nvo_pbnicall(服务端业务代码全由PB编写),具体请看demo客户端代码中的说明; 实现的功能:1.pb客户端调用功能,可实现类似easerver iiop的功能,比easerver多了服务端心跳,客户端自动判断是否断网,自动重连,客户端单开线程序通迅,前端界面不会卡死(用eserver不管是iiop还是ws高锋期经常未响应卡半天),传输码流比easerver小,程序总体运行效率也高一些,支持http get post调用,接口很容易实现;2.客房端点对点发消息(由服务端转发),可以实现类似在线聊天的功能,响应http post也可以通过服务端即时转发给PB的客户端,PB客户端生成响应数据返回http调用端,客户如果用的局域网系统,又想移动端的远程查询(小数据量),软件供应商有公网服务器的话,可用本框架打通实现,我们用此框架实现过医生手机远程连入门诊内部查询修改自已的预约、患者资料;3.服务端即时通知功能,pb长连结客户端、http调用,服务端处理完成后,可以给在线的pb长连结客户端发通知消息,客户端收到通知后可即时出相应操作,例如:酒店系统,前台开房后,全系统房态即时刷新,门诊系统患者前台挂号后,医生端即时就看的到,等等,比客户端轮询来的效果好。
PB9以上的PB版本适用。 使用只有三个函数,很简单。 这是用PBNI编写的控件,VC6的IDE,VC2003的编译器编译,UNICODE版本。 三个函数的使用说明: of_addtip(unsignedlong winhandle, string tip) 添加一个tip。这是必须首先调用的函数,即:在使用其他两个函数前,必须先调用此函数。 winhandle:窗口句柄,操作tip的窗口的句柄,tip的图标即用此窗口的图标。 tip: tip的字符内容。 of_modifytip(string title, string info) 修改tip的内容,并且动态将修改的内容立即显示。参数的含义明显。 of_deletetip() 删除tip. 对tip图标上的鼠标操作的处理: 原理是:图标上的所有windows消息,都会转发到参数winhandle所代表的窗口,作为该窗口的WM_USER消息,即触发该窗口的pbm_custom01事件。pbm_custom01事件的lparm参数指定tip图标的windows消息号。 具体作法:在参数winhandle所代表的窗口的pbm_custom01事件中写代码,检测lparm的值,以判断鼠标进行了哪种操作,如:lparm为517(WM_RBUTTONUP),表示鼠标弹起。 pbm_custom01中的示例代码: //start CONSTANT long WM_MOUSEMOVE = 512 CONSTANT long WM_LBUTTONDOWN = 513 CONSTANT long WM_LBUTTONUP = 514 CONSTANT long WM_LBUTTONDBLCLK = 515 CONSTANT long WM_RBUTTONDOWN = 516 CONSTANT long WM_RBUTTONUP = 517 CONSTANT long WM_RBUTTONDBLCLK = 518 CONSTANT long WM_USER = 1024 CONSTANT long NIN_BALLOONSHOW =(WM_USER + 2) CONSTANT long NIN_BALLOONHIDE =(WM_USER + 3) CONSTANT long NIN_BALLOONTIMEOUT =(WM_USER + 4) CONSTANT long NIN_BALLOONUSERCLICK =(WM_USER + 5) m_base lm_menu CHOOSE CASE lparam CASE WM_MOUSEMOVE // CASE WM_LBUTTONDOWN //鼠标左键按下 CASE WM_LBUTTONUP //鼠标左键弹起 CASE WM_LBUTTONDBLCLK //鼠标左键双击 CASE WM_RBUTTONDOWN // SetFocus ( this ) lm_menu = CREATE m_base lm_menu.PopMenu(PointerX(),PointerY()) DESTROY lm_menu CASE WM_RBUTTONUP // CASE WM_RBUTTONDBLCLK // CASE NIN_BALLOONSHOW // CASE NIN_BALLOONHIDE // CASE NIN_BALLOONTIMEOUT // CASE NIN_BALLOONUSERCLICK // CASE ELSE Beep(0) END CHOOSE //end 注意事项: 经测试,本PBNI如果与其他非UNICODE版的PBNI同用时,会显示乱码。无解。 如有BUG,敬请及时告知。 本控件的讨论贴: http://topic.csdn.net/u/20090510/20/14a57e09-02ca-44df-8f9b-e3811678360d.html

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值