经过一段时间以后的沉淀,对于代码的坏味道的识别能力也渐渐增强。发觉在做开发过程中有一些基础的东西还是很难改变,其中 对缓冲区设计 感觉尤为重要,内存缓冲区,线程池,通信队列等等。有时间一定要好好研究一下缓冲区的设计,现在就让我来记录本次重构遇到的一些问题。
1:链接器到底是如何工作的呢?
在我的项目程序中,程序被分成好几个模块,模块之间有相互作用,为了减少依赖,尽量让文件独立,但是有一个很奇怪的问题是:
比如两个模块分别取名为A, B. B模块的某头文件中引用了一个A模块的一个文件声明IDocument。
如果定义成 对象的形式就会出现链接错误,
CThreadManager<CartoonItem<IDocument>, CDownloadThread<CartoonItem<IDocument>>> m_cartoonTM;
而定义成指针形式就OK.
CThreadManager<CartoonItem<IDocument>, CDownloadThread<CartoonItem<IDocument>>> * m_pCartoonTM;
这到底是为什么呢?
后来重新Build了一下模块,发现不管是指针还是对象,其实都是有链接错误。之所以会出现上述那么奇怪的问题,我想是因为改动太大,由于编译的的增量编译特性导致原
有生成的文件没有被更新。
后来最后修改的的方法就是抛弃IDocument的依赖。
2:STL的 find_if, count_if, mem_fun, mem_fun_ref, bind2nd, 方法.
可以参见 http://topic.youkuaiyun.com/u/20081107/13/8cce2bcb-9ec6-4d65-8404-3424d4746b6b.html; 然后根据这例子代码去查看相关代码的实现,
mem_fun 要求容器存放的是指针,
_Result operator()(const _Ty *_Pleft, _Arg _Right) const
{ // call function with operand
return ((_Pleft->*_Pmemfun)(_Right)); // _Pleft就是迭代器,也就是容器存放的数据类型。
}
所以如果你的容器假设是 class CTest ; vector<CTest> vec; 就不能这样使用了。换成 mem_fun_ref 就可以了。
3:有时候你需要处理很多不同类型的数据,但是又像使用同一个容器,一个容器可以满足不同数据类型存放嘛?好像以前在C++ 沉思录里面看到过,有时间再拿出来翻翻。
待续!
4:在使用FlashDevelop用AS3来加载AS2资源的时候,当调用addChild的时候会出现如下错误
[Fault] exception, information=ArgumentError: Error #2180: 如果 AVM1 内容(AS1 或 AS2)已加载到 AVM2 (AS3) 内容中,则不可将其移动到 displayList 的其他部分。
修改的方法就是在Project窗口, 选中当前工程-》properties->Output 选项卡--》Platform, Flash Player 改成9.00就可以避免该问题了.
5:当在FlashDevelop工程Output中用Flash Player 9.00 Platform来输出文件时,利用Embed(source="../../../../res/assemble_down.PNG")] private var downIcon:Class;方式来实现贴图按钮时却又遇到如下问题:
[Fault] exception, information=VerifyError: Error #1053: 在 mx.core.BitmapAsset 中非法覆盖 z。
查了很多资料,都是说要要将 Output中用Flash Player 9.00 Platform 修改为 Output中用Flash Player 10.0.测试发现是可以,但是这与上面的的情况就很尴尬了,因为服务器
上面已经 有很多AS2发布的资源,不能去将所有的资源都修改成AS3的吧,而且还要考虑版本兼容性问题,最后只好放弃以上实现方式,自己编写代码来实现贴图。方法很简单。
加载资源:
package UI
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class Icon extends Sprite
{
public function Icon(res:String)
{
var ul:URLRequest = new URLRequest(res);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, CompleteResLoad);
loader.load(ul);
}
private function CompleteResLoad(e:Event):void
{
var disObj:DisplayObject = e.currentTarget.content as DisplayObject;
var bmpData:BitmapData = new BitmapData(disObj.width, disObj.height, false);
bmpData.draw(disObj);
var bmp:Bitmap = new Bitmap(bmpData);
addChild(bmp);
}
}
}
6: c++与AS通信的方式?
首先C++加载Shockwave Flash控件,然后通过CallFunction函数,按照Flash规定的格式,向对方传递注册函数及参数,<invoke name>后面的名字就好比是注册函数,AS3必须要用 ExternalInterface.addCallback("ContainCallFunc", ResponseFunc); 对应,ResponseFunc就是AS3的响应函数。也就是说当C++调用CallFunction函数时,
AS3就用ResponseFunc来处理C++传递过来的参数,如果AS3有需要信息需要回传给C++的话,有两种方式: ExternalInterface.call 和 fscommand, c++接受的参数形式会因
因调用方式不同而不同。
C++代码如下
CShockwaveflash1 flashUI;
BOOL CInterActionDlg::OnInitDialog()
{
std::string fileName = "D:\\FlashPrj\\Test\\IconControl\\bin\\IconControl.swf";
flashUI.LoadMovie(0, fileName.c_str());
}
void CInterActionDlg::OnBnClickedOk()
{
//*as3.0 写法: <arguments><string>****</string></arguments> 必须写在一行
this->flashUI.CallFunction("<invoke name=\"ContainCallFunc\">\
<arguments><string>c++1调用flash</string></arguments>\
</invoke>");
//*/
/*as2.0 写法:
this->flashUI.CallFunction(L"<invoke name=\"ContainCallFunc\">\
<arguments>\
<string>c++调用flash</string>\
</arguments>\
</invoke>");
//*/
}
BEGIN_EVENTSINK_MAP(CInterActionDlg, CDialog)
ON_EVENT(CInterActionDlg, IDC_SHOCKWAVEFLASH1, 150/*fscommand*/, CInterActionDlg::FSCommandShockwaveflash1, VTS_BSTR VTS_BSTR)
ON_EVENT(CInterActionDlg, IDC_SHOCKWAVEFLASH1, 197/*ExternalInterface.call*/, CInterActionDlg::ASCallback, VTS_BSTR)
END_EVENTSINK_MAP()
void CInterActionDlg::FSCommandShockwaveflash1(LPCTSTR command, LPCTSTR args)
{
if(0 == strcmp(command, "MsgBox"))
MessageBox(args);
}
void CInterActionDlg::ASCallback(LPCTSTR request)
{
MessageBox(request);
}
AS3代码如下:
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
if (ExternalInterface.available)
{
ExternalInterface.addCallback("ContainCallFunc", ResponseFunc);
}
}
private function ResponseFunc(strCode:String):void
{
//*
var mcw = new MaskContainWnd();
this.stage.addChild(mcw);
//*/
// fscommand("MsgBox", "haohao");
ExternalInterface.call("ASCallback", "fddfd");
}
7: 显示比例错误,怎么办?
在使用C++去加载AS3的代码是,发现最后显示的结果比例不协调,最后发现,原来跟C++利用shockwave的属性有关。注意Slign, Scale, ScalMode的取值。
8:AS3不提供枚举类型,以下形式代码可以用来代替。
package net.smilecn.LibAndMCBind
{
/**
* ...
* @author Zander
*/
public final class FSEnum
{
public static const TASKTYPE_NONEREGISTER:int = 0;
public static const TASKTYPE_AVATAR:int = 1;
public static const TASKTYPE_FASHION:int = 2;
public static const TASKTYPE_3D:int = 3;
public static const TASKTYPE_CUSTOMPHOTO:int = 4;
public static const TASKTYPE_ADV:int = 5;
public static const TASKTYPE_EM:int = 6;
public static const TASKTYPE_ERROR:int = 7;
public static const TASKTYPE_UNKNOWN:int = 8;
}
}
9:BitmapData的缺省函数不是按你所想的那样工作。
在做界面显示的时候,由于这个类的缺省构造函数是透明的,也就真以为是透明的,查看adobe Flash CS3帮助说明才明白,
摘自adobe Flash CS3帮助文档:
transparent:Boolean (default =true
) — 指定位图图像是否支持每个像素具有不同的透明度。 默认值为
true
(透明)。若要创建完全透明的位图,请将
transparent
参数的值设置为 true
,将 fillColor
参数的值设置为 0x00000000(或设置为 0)。
10: stopPropagation() 与 stopImmediatePropagation() 函数对事件处理的优化。
如果有多个窗口是父子关系,为了只让子窗口的消息不透传至父窗口上去,需要对时间进行屏蔽,你需要调用stopPropagation() 函数,也许你也这样做了,但是最后发现
结果还是传给父窗口上去了,那是因为子窗口的其他消息你没有调用stopPropagation()函数导致的。有时父子窗口在焦点获取的时候会激发一些消息事件。他们的事件关系
就好比如下图所示:
所以如果子窗口需要将消息向父窗口进行屏蔽,需要将所有相关的消息统统写上,然后在消息最后写上stopPropagation()函数。stopImmediatePropagation()没尝试过。
对于鼠标类的消息,还有一种粗粒度的方法就是调用 sprite 的 mouseEnable 属性。
11: 多次调用Flash Shockwave控件的 CallFunction 的时候出现 _com_error 异常的原因?
×):检查同一个swf播放器是否多次加载。如:raw_LoadMovie 是否多次调用。
×):检查显示在swf播放器的内容是否在AS端调用了 removeChild .破坏swf播放器的显示。
×):检查第二次调用CallFunction之前AS端是否取消了监听响应( 即:ExterInterface.Callback 第二个参数设置为 null.)
12:线程结束
工作线程
Handler hWorkThread = _beginthreadex(***);
_endthreadex(0);
等待线程
WaitForSingleObject(hWorkThread, INFINIET);
CloseHandle( hWorkThread);
所以就可以用
WaitForSingleObject(hWorkThread, INFINIET)==WAIT_OBJECT_0; 来判断一个线程是否结束,
线程的有无信号可以通过 beginthreadex, endthreadex 来获知。
以下摘自MSDN代码:
// crt_begthrdex.cpp
// compile with: /MT
#include <windows.h>
#include <stdio.h>
#include <process.h>
unsigned Counter;
unsigned __stdcall SecondThreadFunc( void* pArguments )
{
printf( "In second thread...\n" );
while ( Counter < 1000000 )
Counter++;
_endthreadex( 0 );
return 0;
}
int main()
{
HANDLE hThread;
unsigned threadID;
printf( "Creating second thread...\n" );
// Create the second thread.
hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );
// Wait until second thread terminates. If you comment out the line
// below, Counter will not be correct because the thread has not
// terminated, and Counter most likely has not been incremented to
// 1000000 yet.
WaitForSingleObject( hThread, INFINITE );
printf( "Counter should be 1000000; it is-> %d\n", Counter );
// Destroy the thread object.
CloseHandle( hThread );
}
问题:
1:问题?
*)为什么这样做会有问题?
//TCHAR** pResArray = new TCHAR*[5];
//wmemset(pResArray[0], 0, 5);
//wmemcpy(pResArray[0], L"ssss", 5);
*) 注意版本,数据类型
/*
wstringstream ss;
BYTE* sb = new BYTE[5];
memset(sb, 0, 5);
memcpy(sb, "0123", 5);
ss<<sb; //输出:003bc078
//*/
/*
wstringstream ss;
TCHAR* sb = new TCHAR[5];
wmemset(sb, 0, 5);
wmemcpy(sb, L"0123", 5);
ss<<sb; //输出:0123
//*/
stringstream ss;
BYTE* sb = new BYTE[5];
memset(sb, 0, 5);
memcpy(sb, "0123", 5);
ss<<sb;