Profilo di 宗文方寸之间FotoBlogElenchi Strumenti Guida

Blog


12 aprile

如何从第二个线程触发COM事件

有两篇文章说得比较透彻
1)How to start a second thread in an MFC-based ActiveX control to fire events in Visual C++
2)PRB: Firing Event in Second Thread Causes IPF or GPF
 
主要的想法就是用窗口消息将第二个线程想要触发的事件传递到组件的套间线程内部,这样才能满足COM的套间线程模型的假定。
27 marzo

网页中OCX控件HWND为空问题

当网页中的OCX控件没有出现到屏幕上之前(或者尺寸为0时),它的WM_CREATE消息将不会被调用. 这样当script程序调用一些必须要有有效HWND的操作时就会导致MFC/ATL底层库的崩溃(调试版本则会ASSERT)。
 
在MFC中的调试版本:
ASSERT(::IsWindow(m_hWnd));
 
在ATL中的调试版本:
ATLASSERT(::IsWindow(m_hWnd));
 
MFC的解决办法是:在派生类中钩住OnSetClientSite,创建一个窗口,代码如下:
// CMyControl is derived from COleControl.
void CMyControl::OnSetClientSite()
{
  // It doesn't matter who the parent window is or what the size of
  // the window is because the control's window will be reparented
  // and resized correctly later when it's in-place activated.
  if (m_pClientSite)
    VERIFY (CreateControlWindow (::GetDesktopWindow(), CRect(0,0,0,0), CRect(0,0,0,0)));
  COleControl::OnSetClientSite();
}
ATL的解决办法:
// CMyControl is derived from CComControl
STDMETHOD(SetClientSite)(IOleClientSite *pClientSite)
{
  if (pClientSite)
  {
    RECT rc = {0,0,0,0};
    // Don't have access to the container's window so just use the
    // desktop.  Window will be resized correctly during in-place
    // activation.
    HWND hWnd = CreateControlWindow(::GetDesktopWindow(), rc);
    _ASSERT (hWnd);
  }
  return IOleObjectImpl<CMyControl>::SetClientSite (pClientSite);
}
HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
  // Get the container's window.
  _ASSERT (m_spClientSite);
  LPOLEINPLACESITE pInPlaceSite = NULL;
  HRESULT hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void**)&pInPlaceSite);
  _ASSERT (SUCCEEDED (hr) && pInPlaceSite);
  HWND hParent = NULL;
  hr = pInPlaceSite->GetWindow (&hParent);
  _ASSERT (SUCCEEDED (hr) && hParent);
  pInPlaceSite->Release ();
  // Set container window as our parent window
  SetParent (hParent);
  return CComControlBase::InPlaceActivate(iVerb, prcPosRect);
}
 
本文摘自Microsoft原始文档 http://support.microsoft.com/kb/195188/en-us ,略有翻译。
14 agosto

在VC6中安装STLport

进入DOS命令行(cmd)
进入VC安装目录下的vc98\bin子目录
执行vcvars32.bat设置cl需要的环境变量
解压缩到随便一个目录,以下称为目录X
进入目录X下的src子目录
set INCLUDE=目录X\stlport;%INCLUDE%
set LIB=目录X\stlport;%LIB%
copy vc6.mak makefile
nmake clean all
nmake install
此时安装完毕, 头文件被安装到VC安装目录的vc98\include\stlport目录下, 库文件被安装到vc98\lib目录下, DLL被安装到WIN32系统目录下了.
在VC的集成环境中将头文件目录(VC安装目录的vc98\include\stlport)增加在最开始即可
STLport相对于VC6 STL的优点:
1.和linux上用的STL一致
2.增加了hash,超长字符串等不在标准内但常用的模板类
3.代码可读性好
4.Warning少
09 luglio

OCX打包成CAB的方法

以下假定ggg.ocx依赖于bbb.dll,要打包这两个文件需要一个ggg.inf文件,内容如下
;--------------------------------
[Add.Code]
ggg.ocx=ggg.ocx
bbb.dll=bbb.dll
[bbb.dll]
file-win32-x86=thiscab
FileVersion=
DestDir=11
[ggg.ocx]
file-win32-x86=thiscab
clsid={3B951750-8218-4BAC-87EA-C12FCEAB4B6E}
FileVersion=
DestDir=11
RegisterServer=Yes
;------------------------------------------
注意
1) [Add.Code]的安装和设置顺序是倒序的,就是说先安装bbb.dll,然后安装ggg.ocx
2) 其他节[bbb.dll][ggg.ocx]之间的顺序无关紧要
3) 注意版本必须和文件的版本一致,或者不写

采用Visual Studio的集成环境开发Windows核心驱动程序

这是我8年前发表在《计算机世界》上的文章,以这一篇开始我的个人空间的建设吧,呵呵。
 
Microsoft VisualStudio98是一个功能强大的C和C++程序开发环境, 其中有几项功能我(相信也是广大C和C++程序员们)特别喜欢:彩色句法敏感, 源代码浏览, 类和文件浏览, 直接定位语法错误等等.
然而, 这么好的工具, 却让很多NT kmode驱动程序开发者非常恼火, 因为她(他)并不能直接使用VS98. MS所提供的是一个史前的难用的命令行工具build!
不必说build运行时产生的许多令人精神错乱的last line incomplete, 最麻烦的是改错以及查找函数的申明和定义了.
其实, build也使用与VS同样的编译和连接器, 对VS稍做定制, 我们就可以方便地使用集成IDE.
1. 创建kmode项目:
从VS98中选择File/New菜单项, 然后生成一个新的Win32 Dynamic-Link Library项目.
2. 更改All Configurations选项:
选择Project/Settings/All Configurations, 转到C/C++标签, 作如下改动:
2.1在Category "C/C++ Language"中去除Enable exception handling.
2.2在Category "Code Generation"中选定Calling convention为__stdcall,以
及Struct member alignment为8-bytes.
2.3在Category "Precompiled Headers"中设定"Not using...".
2.4在Category "Preprocessor"中输入定义_X86_=1,i386=1,STD_CALL=1,
CONDITION_HANDLING=1,WIN32_LEAN_AND_MEAN=1,NT_UP=1,
NT_INST=0,WIN32=100,
_NT1X_=100,WINNT=1,_WIN32_WINNT=0x0400,
DEVL=1,NDEBUG,_DLL=1,_IDWBUILD,
DBCS,PRC,KKBUGFIX,DBCS_VERT,FE_SB.
并增加include目录d:\ddk\inc
(如果你安装DDK时的设定不同于此,请写你的设定值).
转到Link标签,定制如下:
2.5在Category "General"中去除Generate debug info并选定Ignore all
default libaries和Doesn't produce .LIB.在Object/library modules中加上你
要连接的库,一般是int64.lib ntoskrnl.lib hal.lib.
2.6在Category "Custom"中去除Program database复选框.
2.7在Category "Output"中设定Entry-point symbol为DriverEntry@8.
转到Resource标签,增加d:\ddk\inc到
include目录,并定义符号_X86_=1,i386=1,
STD_CALL,CONDITION_HANDLING=1,
NT_UP=1,NT_INST=0,WIN32=100,_NT1X_=100,WINNT=1,
_WIN32_WINNT=0x0400,WIN32_LEAN_AND
_MEAN=1,DEVL=1,NDEBUG,_DLL=1,_IDWBUILD,
DBCS,PRC,KKBUGFIX,DBCS_VERT,FE_SB.
3. 定制Win32 Debug选项(即checked build):
选择Project/Settings/Win32 Debug, 转到C/C++标签, 作如下改动:
3.1在Category "General"中选择Debug info
为C7 compatible.增加DBG=1,FPO=0,
RDRDBG,SRVDBG这几个符号到
Preprocessor definitions中的符号之前.并在
Project Options的最后添加
/GF /QIfdiv- /QIf三个编译选项.
转到Link标签,定制如下:
3.2在Category "General"中设定输出文件为
Debug\mydriver.sys(你要产生的sys文件).然后在Project Options的最后添加/libpat
h:"d:\ddk\lib\i386\checked"
/Subsystem:native这两个连接选项.
转到Resource标签,增加符号定义DBG=1,FPO=0, RDRDBG,SRVDBG.
遗憾的是, 不能从VS中调试kmode驱动程序, 这只好等MS的改进了, 可是现在我们只好用
WinDbg. 且慢, 我们不能使用采用刚才设置的选项连接出来的.sys文件调试, 因为WinD
bg
要求连接时采用/Debug:FULL和/debugtype:both选项, 可是VS98不同时支持二者
(你可以试试). 一种解决办法是在连接完成后删 除.sys文件, 手工(从命令行上)运行
link, 那多扫兴哪. 实际上VS可以自动在连接完成后运行一些命 令, 只要你转
到Post-Build step标签设置一下就可以了. 我是这样设置的:
link /nologo @mydriver.lnk
rebase -b 0x10000 -x Debug Debug\mydriver.sys
if exist Debug\mydriver.dbg del /f Debug\mydriver.dbg
move Debug\sys\mydriver.dbg Debug
rd Debug\sys
产生的调试文件mydriver.dbg你可记得要拷贝到调试控制机的winnt\symbols\sys
目录下哟. 其中mydriver.lnk是一个link命令文件,
内 容 如 下:
-machine:i386
-MERGE:_PAGE=PAGE
-MERGE:_TEXT=.text
-SECTION:INIT,d
-OPT:REF
-INCREMENTAL:NO
-FORCE:MULTIPLE
-RELEASE
-FULLBUILD
-IGNORE:4001,4037,4039,4065,4070,4078,4087,4089,4096
-NODEFAULTLIB
-debug:notmapped,FULL
-debugtype:both
-version:4.00
-osversion:4.00
-PDB:NONE
-MERGE:.rdata=.text
-optidata
-driver
-align:0x20
-subsystem:native,4.00
-base:0x10000
-entry:DriverEntry@8
-out:Debug\mydriver.sys
Debug\mydriver.res
Debug\mydrv1.obj
Debug\mydrv2.obj
D:\DDK\lib\i386\checked\int64.lib
D:\DDK\lib\i386\checked\ntoskrnl.lib
D:\DDK\lib\i386\checked\hal.lib
这一长串命令是从build.log中paste到的, 有什么疑惑可以参考联机手册.
现在大部分已经自动化了, 稍有点不方便的是增加一个源文件时要在.lnk文件中相
应增加一行.obj, 可是世上不如意事所在多有, 那也无可如何了. 好在你不会频繁增
加源文件吧.
4. 定制Win32 Release 选 项(即free build), 就简单多了.
选择Project/Settings/Win32 Release, 转到C/C++ 标签, 作如下改动:
4.1在Category "General"中选择Debug info
为None.增加FPO=1到Preprocessor
definitions中的符号之前.然后选择你喜欢的优化方法.
转到Link标签,定制如下:
4.2在Category "General"中设定输出文件为
Relase\mydriver.sys.然后在Project
Options的最后添加/libpath:"d:\ddk\lib\i386\free" /Subsystem:native.
转到Resource标签,增加符号定义FPO=1.
好, 一切设定完成. 增加你的源文件到Project之后, 可以按F7(构造)了,
体会一下VS98这种利器开发kmode驱动程序的快捷方便的感觉, 相信那与
build是大不一样的.
本文有一些部分内容参考了MSDN的文 章"The Windows NT Kernel-Mode Driver
Cookbook, Featuring Visual C++" 的说法(谢谢作者Ruediger R.Asche), 但
大部分是我自己的工作经验, 希望对大家有所帮助.