自己接触的项目基本都是用vc2003写的.这几天因为贪图vc6.0写的dll小(不必静态连接嘛).所以用上了这个"老家伙".而以前的程序都不是UNICODE字符集的,考虑到国际化,所以这个DLL就用UNICODE字符集了. dll的接口定义好后,又写了几个类.然后用MFC对话框程序来测试这个dll.可要命的是,vc6老是提示有内在泄露.如下:Detected memory leaks!Dumping objects ->{51} normal block at 0x003B2E80, 33 bytes long. Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD {50} normal block at 0x003B2E18, 40 bytes long. Data: < |L > 14 7C 4C 10 16 00 00 00 00 00 00 00 00 00 00 00 Object dump complete. 我检查了所有该释放内存的地方都释放了.还是提示内在泄露...我动用了内存泄露检查工具(AQTime5),却没找到有内存泄露的地方...是怎么回事呢? 最后,我只是在测试工程里加上dll导出来的api,而没有调用.还是提示有内在泄露...怎么回事?我确认,如果dll导出的api没有被调用,dll里就绝对不会有对象被实例化! 可是,这样怎么还是说有内在泄露?我要抓狂了:(.... 没法,还是要找到问题出在哪里啊.我就把dll的类一个一个注释掉,把dll中的文件从工程中一个一个移除掉...把一个类里的一个变量或一个成员函数注释掉...终于发现是在一个线程类里有这样一个成员变量:wstring m_strThreadName,只要注视掉它,就不会有内在泄露的提示,只要加上就有. 真晕,这个线程类都还没有被实例化呢.为了验证是vc6生成长歪了,我用它写了一个很简单的dll,只导出一个add的api,这个api做了一个1+1的运算,然后返回. 测试后,没问题.我又增加了一个类,并加上了一个成员变量: wstring m_name,不实例化它. 再次测试果然提示有内存泄露,和前一个dll的提示一模一样!! 我晕菜后醒来,真想拿头撞墙,最后考虑再三,只是一口气做了N个俯卧撑(N<=5,发现右手经常握鼠标,经年累月后,在手腕和手掌关节处的骨头长长了,成不了90度了.做俯卧撑时疼痛难忍,看样子,要经常锻炼身体才对) 用vc2003或以上的版本测试,没有这个内存泄露的提示. 哎,应该彻底的把vc6仍到厕所里了(对模板支持太差,可也怪不了人家,它出生太早).说不定又会莫名其妙的闹鬼....
posted @
2008-05-10 00:24 冰风谷 阅读(1026) |
评论 (2) |
编辑 收藏
昨天晚上写COM组件时突然碰到创建一个COM对象时,返回0x80040154,没有注册类型...搞得一头雾水.检查了创建函数,参数,GUID,注册表中的各项都正常.... 最后没辙了,只能新建一个COM工程试试,结果也是一样的(在同一个工程中测试).后来又新建了一个测试工程,也重新编译COM工程,结果却返回E_NOINTERFACE,晕啊.创建的对象明明支持这个接口的啊.我追踪到ATL的代码里,发现我查询的接口确实找到了,但最后还是返回E_NOINTERFACE. 经过几次调试,发现老是查询IMarshaling等几个与列集有关的接口,f却总找不到....后来在网上找到了一篇文章,找明白了一些. 参考:http://blogs.msdn.com/oldnewthing/archive/2004/12/13/281910.aspx
Why do I get E_NOINTERFACE when creating an object that supports that interface?
I've seen a few questions from people who call
the CoCreateInstance
function,
asking for an interface that they know the object supports,
yet receiving error E_NOINTERFACE
.
What's going on?
You're seeing
the same problem as the missing IMarshal,
just from the other side.
If your threading model is incompatible with the threading model
of the object you're creating, then COM marshalling kicks in.
And if the marshalling stuff isn't there, the error that comes
out is E_NOINTERFACE
, because the marshalling interface
is missing.
A common source of this is attempting to use COM objects provided
by the shell from a multi-threaded apartment. Remember that shell
COM objects are, for the most part, apartment-threaded, not
free-threaded.
If you want to use shell objects, you should do so from single-threaded
apartments.
Published
Monday, December 13, 2004 8:51 AM
by
oldnewthing
Filed under: Code
------------------------------
后来我看了下我的测试工程是/MDd,而COM工程的线程模型是Free,改成Apartment就好了.解释如上.但我愚钝,还是一知半解,五一好好钻研下这两个问题:
1.没有注册类型
2.E_NOINTERFACE
posted @
2008-04-29 11:35 冰风谷 阅读(4773) |
评论 (0) |
编辑 收藏
做vc开发两年了,很少做界面开发,最多就是一个对话框,上面放几个按钮,再放上几个static text显示程序运行信息。目前做广播源和镜像服务器,按钮多了点,感觉很乱,就加上了菜单。可是发现有一个菜单项不管怎么弄都显示灰色,已经响应Update UI消息了... 后来才发现是菜单项ID重复了,NND....
posted @
2008-01-12 21:38 冰风谷 阅读(2848) |
评论 (0) |
编辑 收藏
今天周六,孤家寡人,无所事事,正好拿出刚从china-pub上购买的书"深入解析ATL"第二版来看看...
以前一直对COM比较感兴趣,也囫囵吞枣的看了些关于COM的书籍,限于功力有限,也一直没从事COM方面的工作。时到今日,还是个“糊涂神”...由于现在的工作不再像以前那样处处受限于人,自由度比较大,很多时候自己可以拿主意了。所以在做模块化时,何不用COM来做做?
刚看了一点,看到线程套间的时候,还是如以前那么模糊,于是想google下,是否能查到哪位神人写了一篇神帖,让我一下豁然开朗。果然从www.vckbase.com上搜到了一篇"
理解 COM 套间"的帖子,作者
junguo。看了下简述,为作者曾经失去的一段感情感到惋惜,COM居然也能参入其中,真是不可小看,呵呵。
很赞同作者的话,你想学好一个东西,就必须先弄明白这个东西产生的背景和原因。其间,作者说到多线程,说到了汇编...于是我去看了下各寄存器的功能...说到了线程同步,发现作者在调用InitializeCriticalSection初始化CRITICAL_SECTION后没有释放,但我一时记不起释放的函数了,于是在msdn里搜下InitializeCriticalSection 这个API,就找到了DeleteCriticalSection,就它释放临界区了。一般创建资源和释放资源的API,在msdn里总是互相引用,成双成对的嘛。但我突然发现了初始化临界区的另一API:
InitializeCriticalSectionAndSpinCount,它是干嘛的?比InitializeCriticalSection来多了什么功能?在什么情况下不使用InitializeCriticalSection,而使用
InitializeCriticalSectionAndSpinCount?
看MSDN,虽然能看懂,但还是嫌慢了点,就又google了下,发现了这篇文章:http://yjl.spaces.live.com/blog/cns!8129C4219A8E995B!466.entry.突然间想起了上周末,我在看的Lock-Free, Wait-Free...想起有一个地方说实现spin lock的意义。当时也没在意,呵呵,现在一想起来,原来ms为我们实现了不少东东:CAS,可用InterlockedCompareExchangePointer来实现,就是CAS2没找到对应的实现,应该是一个64位的API,没仔细的去找。而现在又突然发现
spin lock可以用InitializeCriticalSectionAndSpinCount来代替,哈哈....
哎哎,游得太远点了,我回去了。不过先回“理解 COM 套间”这篇文章再说,还没看完呢。看完了再回书上...看腻了,就开始做做UDP直播的镜像吧,这回可是有一个月工资的奖金的...
posted @
2008-01-05 14:54 冰风谷 阅读(713) |
评论 (3) |
编辑 收藏
以前一直把word当字处理软件来使用,所有的格式都是自己空格,回车,手动输入1,2,3...来分类...文档还没写几页,就觉得整个版面丑陋不堪...看着看着就失去了继续写下去的兴趣....
实在受不了不会排版的郁闷了,就到网上下了“Word排版艺术[候捷]2004”来学习....
每天抽时间来学学,也不亦乐呼
期待学习漂亮的排版在我的敲打下现身....
posted @
2008-01-04 00:03 冰风谷 阅读(252) |
评论 (0) |
编辑 收藏
最近在写一个网络诊断的小程序,由于粗心大意或说自己的初始化意识不够强,造成了被主管"鄙视"的事态,哈哈。笑完后,告诉自己,以后碰到使用数据结构的地方,就当是碰到指针一样,不管三七二十一,初始化先。
在Debug下不初始化数据结构或句柄啥的没关系,因为Debug下,VC替你做了。但在Release下就会出现不确定的行为。有时可以,时不可以....
比如在CListCtrl中改变图标的一段代码:
1void CPSDiagDlg::ChangeImage(int nItem,int nImg)
2{
3 LVITEM item;
4
5 //memset(&item,0,sizeof(LVITEM));
6 item.iItem = nItem;
7 m_list.GetItem(&item);
8 item.mask = LVIF_IMAGE;
9 item.iImage = nImg;
10 m_list.SetItem(&item);
11} 这段代码在Debug下运行得很好,但在Release却没什么影响,偶尔能改变图标(换图标)。如果把注释掉的5行放开,一切ok.
还有一段发送UDP数据包的代码:
创建sock:
1BOOL CPSSvrTester::CreateSocket(WORD wPort)
2{
3 if (m_socket != INVALID_SOCKET && m_wPort != wPort)
4 {
5 closesocket(m_socket);
6 m_socket = INVALID_SOCKET;
7 }
8 if(m_socket == INVALID_SOCKET)
9 {
10 sockaddr_in local;
11 //wPort = 6002;
12 if(wPort)
13 m_wPort = wPort;
14
15 local.sin_family=AF_INET;
16 local.sin_addr.s_addr=0;
17 local.sin_port=htons(m_wPort);
18
19 WORD wTmpPort = wPort;
20 int iTimes = 0;
21
22 m_socket = socket(AF_INET, SOCK_DGRAM, 0);
23 while(bind(m_socket,(sockaddr *)&local,sizeof(sockaddr_in)) == SOCKET_ERROR)
24 {
25 closesocket(m_socket);
26 iTimes++;
27 if(iTimes>10)
28 break;
29 //m_socket = INVALID_SOCKET;
30 if(wPort)
31 local.sin_port = htons(++wTmpPort);
32 m_socket = socket(AF_INET, SOCK_DGRAM, 0);
33 }
34 if(iTimes<=10)
35 {
36 int inamelen = sizeof(local);
37 if(getsockname(m_socket,(SOCKADDR *)&local,&inamelen ) == SOCKET_ERROR)
38 {
39 closesocket(m_socket);
40 m_socket = INVALID_SOCKET;
41 return FALSE;
42 }
43 m_wPort = ntohs(local.sin_port);
44 }
45 else
46 {
47 closesocket(m_socket);
48 m_socket = INVALID_SOCKET;
49 return FALSE;
50 }
51 int TimeOut=2000;
52 setsockopt (m_socket, SOL_SOCKET,SO_RCVTIMEO,(CHAR *) &TimeOut,sizeof (TimeOut));
53 return TRUE;
54 }
55 return TRUE;
56} 发送UDP数据包的代码:
1BOOL CPSSvrTester::Send(BYTE *pData, DWORD dwDataLen, DWORD dwSendTo, WORD wPort)
2{
3 if (m_socket == INVALID_SOCKET)
4 {
5 return FALSE;
6 }
7 SOCKADDR_IN remote;
8 int iRet;
9 remote.sin_family = AF_INET;
10 remote.sin_port = htons(wPort);
11 remote.sin_addr.s_addr = dwSendTo;
12 iRet = sendto(m_socket,(const char*)pData,dwDataLen,0,(SOCKADDR *)&remote,sizeof(remote));
13 if(iRet<=0)
14 return FALSE;
15 return TRUE;
16} 在Debug下先调用CreateSocket,然后调用Send发送数据,每次都ok.因为Debug,vc已把m_sock初始化为INVALID_SOCKET。而在Release下就完罗,怎么也发不了数据,因为CreateSocket里的代码根本没执行!
在构造函数中添加:m_sock = INVALID_SOCKET;一切ok!
posted @
2006-09-03 00:19 冰风谷 阅读(964) |
评论 (0) |
编辑 收藏
真是郁闷极了,刚起来一看,又是晚上7点了!周六又这样过去了,而我什么都没有学到。
早上起来已是近10点。进入现在的公司后,工作上特别充实,当然也特别容易疲倦。住的地方离公司又远,每天下班回家花一个多小时,到家后一身的汗。洗个澡,换套衣服,然后打开电脑,放首歌,然后煮面吃...端着面看会新闻或自己喜欢的电视或打开ppstream看看有没有好看的电视电影或上ppstream论坛,或上csdn社区或上自己的gmail看下订阅的文章....
一会功夫就到10点了。一天的困意也随之而来。天啊,我还有很多的东西要学啊。网络编程,流媒体,p2p....基础的数据结构,算法等...看来,不是科班出身的进入这行,要做好这行,占有一定的地位,还是很辛苦的,而我已经辛苦两年了!两年了,就是从只会聊天,连if...else都不会写,爬到今天...从刚入这行时的800到现在的8倍...
ppstream,我一直看好的产品,也有幸能参加到它的开发中来...但我的基础真的太薄弱,要学的太多...可是现在却总没时间学习,连周末也被自己这样浪费着,不可原谅!!
在我们小组,就我的资历最低了吧。他们都在c++中开发了5,6年了,就我两年,而且头一年还是做vb,真正接触vc(c++)还差几天才到一年...呵呵。任务重啊。。。
我应该好好的反省一下,好好的重新制定一份时间的管理方案...
今天我集中鄙视一下自己这种大度挥霍时间的人一次...
posted @
2006-08-26 19:16 冰风谷 阅读(284) |
评论 (0) |
编辑 收藏
这是自己在编程中碰到的一些问题。太讨厌做界面了,但必需得做,就算做服务器软件也得有一个简单界面呢。
1、加入图片
1
CImageList imaSmall;
2
imaSmall.Create(IDB_SMALLBMP,
16
,
0
,RGB(
0
,
128
,
128
));
3
m_RecvList.SetImageList(
&
imaSmall,LVSIL_SMALL);
也可以调用loadImage,然后用CImageList的Add...
注意:一般要来,在调用CListCtrl的SetImageList时,都用LVSIL_SMALL。否则可能不能显示
2、插入项(report)
最简单的就是
int InsertItem( int nItem, LPCTSTR lpszItem, int nImage );
如果用LVITEM结构来插入的话,稍微注意一点:
int nItem = m_list.GetItemCout();
a.插入一项
LVITEM item;
item.mask = LVIF_IMAGE|LVIF_TEXT;
lvItem.iItem =nItem ;
lvItem.iSubItem = 0; //一定要设为0
lvItem.iImage=imageindex; //图片的索引
lvItem.pszText = (LPTSTR) file;
m_list.InsertItem(&lvItem); b.插入一子项
tem.mask = LVIF_TEXT;
lvItem.iItem =nItem ; //某一项下的子项
lvItem.iSubItem = 1; //一定要设为大于1的值
lvItem.pszText = (LPTSTR) file;
m_list.InsertItem(&lvItem); 3、修改某一项的属性
4、查询某一项
posted @
2006-08-24 15:02 冰风谷 阅读(1241) |
评论 (0) |
编辑 收藏
这几天在做一个网络诊断的工具。用到两个线程:
界面线程:界面是一个对话框。在对话框上有一个进度条。
工作线程:执行检测的工作。并把对各项的检测结果以自定义消息发送给界面线程,让它呈现出来...
我定义了一个消息:#define WM_SETPROGRESS WM_USER + 105
//设置进度条的进度
然后每检测完一项后,用PostMessage向界面线程发送WM_SETPROGRESS消息。就出现不正常的现象。比如我已检测完一类的进度,现在想检测另一类的,所以我要重新设置一个范围(SetRange(0,100))和一个新的位置(SetPos(0)),但好像并没有执行。还是前一类检测完后的进度。
如果在工作线程中用一个循环不断的post消息,结果只处理了一小部分的消息。即:
[工作线程中]
for(int i=1;i<=100;i++)
{
PostMessage(m_hWnd,WM_SETPROGRESS,i,0);
}
用SendMessage代替PostMessage,处理得更好一些。因为可以看到进度条的进度更长些,但也只显示了不到一半的进度...
如果把对话框对象指针传递给工作线程,在那里调用SetPos,进度条就工作的很好...
posted @
2006-08-22 10:50 冰风谷 阅读(2011) |
评论 (2) |
编辑 收藏