Sciter教程_01_分析minimal例程

本文介绍了如何在SciterSDK的minimal例程中编译并运行,涉及文件加载、窗口创建、消息循环以及资源文件从内存、res目录和archive的加载。作者详细解释了WinMain函数和SciterCallback的作用,并展示了如何通过回调函数处理不同类型的文件加载请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sciter教程系列-01 分析sdk/demos/minimal例程

编译demos/minimal例程

上一个教程已经搭建好工程运行起来了,现在将VS项目中src目录下的源码文件移除(不是删除),然后将$(SciterSDK)/demos/minimal/minimal.cpp拷贝到src/并添加到VS工程中。编译运行,将会得到如下结果。

在这里插入图片描述

控制台提示无法加载bin/minimal.htm文件,显然代码中指定了加载此文件,但是本地磁盘没有该文件。为了显示本地文件,将res/main.htm拷贝到bin/目录下,将代码中的minimal.htm改为main.htm,再次编译运行即可看到本地的文件被加载成功并显示出来。

接下来分析minimal.cpp中的代码。

程序入口WinMain

代码使用win32-api创建了一个窗口并加载本地.htm资源文件,有关程序入口WinMain的描述见WinMain function

在这个程序入口函数里,主要完成两件事,通过sciter加载文件、创建窗口并建立消息循环。

1、sciter加载文件。sciter可以通过回调函数使得用户可以自定义文件加载的方式。如下代码中,函数SciterCallback实现中分发了系列回调事件,其中就包括了加载文件的回调函数,当SciterLoadFile加载文件时,执行的其实是自定义的加载文件回调函数DoLoadData。而在DoLoadData中,将根据指定的资源文件路径的字符串格式来区分资源从内存导入、从res/导入、从resources.cpp导入或者是从绝对路径导入。

::SciterSetCallback(wnd,&SciterCallback,NULL);
::SciterLoadFile(wnd, GetAbsolutePath());

示例中使用了指定绝对路径导入资源文件的方式。

2、创建窗口并建立消息循环。这里使用的都是win32-api,具体函数用法可参考Programming reference for the Win32 API。创建窗口消息循环相关可参考Creating a Message Loop

HWND wnd = ::CreateWindowEx(
		0, /*WS_EX_LAYOUTRTL,*/
		::SciterClassName(),
		L"Minimal Sciter Application",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0,
		800, 600,
		0,0,0,0);

::ShowWindow(wnd, SW_SHOWNORMAL);

MSG msg;
while( ::IsWindow(wnd) && GetMessage(&msg, 0, 0, 0) )
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

资源文件改为从resources.cpp加载

按照上一个教程中资源文件路径指定的方式,修改main.htm的路径。编译运行,发现窗口正确显示了,但是资源文件未加载。

// ::SciterLoadFile(wnd, GetAbsolutePath());
::SciterLoadFile(wnd, WSTR("this://app/main.htm"));

调试发现,在DoLoadData中,分支代码的::SciterDataReady并未被执行,具体来说,是sciter::archive::instance().get()方法没有取到所需的资源数据。对比上一个教程的代码可以看到,其中有加载resources.cpp数据的动作,而resources.cpp又是使用打包脚本打包资源文件得到的,加上以下两行代码,再编译运行,可以看到资源文件成功加载。

#include "resources.cpp"
sciter::archive::instance().open(aux::elements_of(resources));

修改后的minimal.cpp

// minimal.cpp : minimal Sciter application.

#include <windows.h>

#include "sciter-x.h"

#include "resources.cpp"

HINSTANCE ghInstance = 0;

// generate BGRA image
// check http://sciter.com/forums/topic/how-to-render-memory-image-in-sciter-page/
void GenerateBGRATestsImage(HWND hSciter) {
  BYTE packedData[4 + 4 + 4 + 10 * 10 * 4]; 
  memset(packedData,0,sizeof(packedData));

  // signature
  packedData[0] = 'B';
	packedData[1] = 'G';
	packedData[2] = 'R';
  packedData[3] = 'A';

  // width/height
  packedData[7] = 10;
  packedData[11] = 10;

  // image data
  for ( int i = 0; i < 10 * 10 * 4; i += 4)
  {
			packedData[4 + 4 + 4 + i] = i / 4;
      packedData[4 + 4 + 4 + i + 1] = 255 - i / 4;
      packedData[4 + 4 + 4 + i + 2] = 255;
      packedData[4 + 4 + 4 + i + 3] = 255;
  }
  ::SciterDataReady( hSciter, WSTR("in-memory:test"), packedData,  sizeof(packedData));
}

// handle SC_LOAD_DATA requests - get data from resources of this application
UINT DoLoadData(LPSCN_LOAD_DATA pnmld)
{
  LPCBYTE pb = 0; UINT cb = 0;
  aux::wchars wu = aux::chars_of(pnmld->uri);

  if(wu == const_wchars("in-memory:test"))
  {
    // 从内存加载
    GenerateBGRATestsImage(pnmld->hwnd);
  }
  else if(wu.like(WSTR("res:*")))
  {
    // then by calling possibly overloaded load_resource_data method
    if(sciter::load_resource_data(ghInstance,wu.start+4, pb, cb))
      ::SciterDataReady( pnmld->hwnd, pnmld->uri, pb,  cb);
  } else if(wu.like(WSTR("this://app/*"))) {
    // try to get them from archive (if any, you need to call sciter::archive::open() first)
    aux::bytes adata = sciter::archive::instance().get(wu.start+11);
    if(adata.length)
      ::SciterDataReady( pnmld->hwnd, pnmld->uri, adata.start, adata.length);
  }
  return LOAD_OK;
}

// fulfill SC_ATTACH_BEHAVIOR request 
UINT DoAttachBehavior( LPSCN_ATTACH_BEHAVIOR lpab )
{
  sciter::event_handler *pb = sciter::behavior_factory::create(lpab->behaviorName, lpab->element);
  if(pb)
  {
    lpab->elementTag  = pb;
    lpab->elementProc = sciter::event_handler::element_proc;
    return TRUE;
  }
  return FALSE;
}

// 窗口回调函数
UINT SC_CALLBACK SciterCallback( LPSCITER_CALLBACK_NOTIFICATION pns, LPVOID callbackParam )
{
  // here are all notifiactions
  // 根据回调码执行实际的回调函数。其实就是一个事件响应
  switch(pns->code) 
  {
    // 响应加载文件
    case SC_LOAD_DATA:          return DoLoadData((LPSCN_LOAD_DATA) pns);

    // 响应行为挂载
    case SC_ATTACH_BEHAVIOR:    return DoAttachBehavior((LPSCN_ATTACH_BEHAVIOR)pns );
  }
  return 0;
}

LPCWSTR GetAbsolutePath() {
  static WCHAR url[MAX_PATH] = {0};
  GetModuleFileName(NULL,url,MAX_PATH);// 获取exe可执行文件的绝对路径,其实就是bin/这个路径
  WCHAR* t = wcsrchr(url,'\\');// 找到最后一个反斜杠的位置
  assert(t);

  // 把反斜杠连同后边的exe名清零
  while (*t)
  {
    *t = 0;
    ++t;
  }

  // 继续找上一个反斜杠,这样就找到了父级目录lhy,再定位到res/main.htm
  t = wcsrchr(url,'\\');// 找到最后一个反斜杠的位置
  assert(t);
  wcscpy(t + 1, L"res\\main.htm");

  // wcscpy(t + 1,L"main.htm");// 将路径中的xxx.exe替换成main.htm,定位到目标htm。这种方式要把main.htm拷贝到bin目录中
  return url;
}

// CALLBACK-调用约定,回调函数,系统负责调用,具体由用户实现
// 具体参考:https://blog.csdn.net/yaked/article/details/52354921
int CALLBACK WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
  ghInstance = hInstance;// 保存实例id到全局实例
  OleInitialize(NULL); // for shell interaction: drag-n-drop, etc.


  // Enable these features, to be available from script 
  // SciterSetOption(NULL, SCITER_SET_SCRIPT_RUNTIME_FEATURES, 
  //  ALLOW_FILE_IO |
  //  ALLOW_SOCKET_IO |
  //  ALLOW_EVAL |
  //  ALLOW_SYSINFO);

  // enabling interaction with inspector:
  ::SciterSetOption(NULL, SCITER_SET_DEBUG_MODE, TRUE);

  // or un-comment the following to see console output: 

  sciter::debug_output_console _;
  
  // windows api 创建窗口,返回创建窗口的句柄
  // HWND - Handle of Window
	HWND wnd = ::CreateWindowEx(
		0, /*WS_EX_LAYOUTRTL,*/
		::SciterClassName(),
		L"Minimal Sciter Application",
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0,
		800, 600,
		0,0,0,0);

  // 设置回调函数
  ::SciterSetCallback(wnd,&SciterCallback,NULL);
  
  // 加载htm文件,也可以指定特定路径
	// ::SciterLoadFile(wnd, GetAbsolutePath());

  // 包含进来的resources.cpp是运行打包脚本生成,里边有个resources数组,这里将数组内容读到sciter::archive的单一实例对象中
  sciter::archive::instance().open(aux::elements_of(resources)); // bind resources[] (defined in "resources.cpp") with the archive
  // note: this:://app URL is dedicated to the sciter::archive content associated with the application
  // 以这种形式加载,会从sciter::archive中读到的资源文件加载
  ::SciterLoadFile(wnd, WSTR("this://app/main.htm"));

  //const char* css = "html {background:red}";
  //::SciterSetCSS(wnd, (LPCBYTE)css, strlen(css), L"about:blank", L"");

	::ShowWindow(wnd, SW_SHOWNORMAL);
  //::SciterLoadFile(wnd, GetUrl());

/*  sciter::value undefined, map = sciter::value::from_string(aux::chars_of(L"{'0': 0, '1': 1, '2': 2, '3': 3}"), CVT_JSON_LITERAL);
  map.set_item(L"1", undefined);
  map.set_item(L"3", undefined);
  sciter::string s = map.to_string(CVT_JSON_LITERAL);
  s = s; */

  // 消息循环
	MSG msg;
  while( ::IsWindow(wnd) && GetMessage(&msg, 0, 0, 0) )
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值