MiniGUI使用之关于皮肤窗口的skin_init和skin_deinit的疑问

关于皮肤窗口的skin_init和skin_deinit的疑问?

最近学习使用MiniGUI的皮肤窗口,在使用标签控件过程中出现了一些奇怪的问题:

为了使用图片标签,我在一个子窗口模块中定义了一个模块级的si_bmplabel_t变量。按照通常程序我对skin_head_t进行了声明,然后调用skin_init进行了初始化,显示窗口,操作一番,退出时,由于skin_head_t变量是动态创建的,于是对其进行释放,释放前我调用了skin_deinit。一切都很正常,但是在我尝试第二次进入这个窗口时,问题出现了,标签显示不正常。为了搞清楚原因对MiniGUI源码进行了跟踪。原来是MiniGUI在skin_init和skin_deinit中的处理导致了模块级变量属性的意外丢失。

首先来看一下si_bmplabel_t的定义:
typedef struct si_bmplabel_s
{
   /** The label string. */
   char* label;
   /** All label characters in the bitmap. */
   const char* label_chars;
} si_bmplabel_t;
其中,label记录着标签的显示值,label_chars记录的是标签所使用的字符图片的字符序列。

在skin_init中针对图片标签会进行特殊的初始化,该初始化由下面这个函数完成:
static int bmplabel_init (skin_head_t* skin, skin_item_t *item)
{
   DECL_LABEL ( si_bmplabel_t, 0);
   //注意下面这句:
   mylabel->label = strdup ( mylabel->label ? mylabel->label : EMPTY );

   return 1;
}

DECL_LABEL的定义如下:
#define DECL_LABEL(type,ret) /
   type *mylabel = (type *) item->type_data; /
   if (!mylabel) return ret;

这个函数干了什么事情呢?它将item的type_data属性转变为一个si_bmplabel_t的指针,然后把这个si_bmplabel_t变量的label复制一遍再赋给这个label。也就是说原来的那个label记录的指针已经丢失了。如果这个label指向的是一个动态申请的字符串,而代码中恰好没有其他的指针指向它,那么很遗憾,这段内存已经泄漏。
再来看看MiniGUI中skin_deinit和skin_set_item_label都干了什么:
skin_deinit会调用下面这个函数对标签属性进行释放,
static int bmplabel_deinit (skin_item_t *item)
{
   DECL_LABEL ( si_bmplabel_t, 0);

   if (mylabel->label) free (mylabel->label);

   return 1;
}

skin_set_item_label调用set_label函数实现对标签属性的设置。
在set_label (skin_item_t *item, DWORD label)函数中下面的代码则负责对原label指向字符串的释放:
   if (mylabel->label) free (mylabel->label);
       mylabel->label = strdup (new_label);

MiniGUI对自己还是很负责的,进行了复制,当然要进行释放了。
不过,遗憾的是,这么一去一来,调用skin_deinit进行皮肤释放后,用户自己定义的si_bmplabel_t变量的label也一起被释放了。别忘了这个label指针仍然尽职尽责的指向最后strdup复制的字符串,尽管这个字符串已经被skin_deinit释放了。

既然MiniGUI为了防止外部代码对控件内部属性的直接访问(实际上skin_set_item_label还要做很多事以确保显示的正确性)。是不是也应该考虑这么做对外部代码的影响。或者干脆就直接对si_bmplabel_t变量进行复制,这样不是更保险么?

你可能感兴趣的:(MiniGUI,Linux)