2009年4月11日星期六

Posted by Picasa

2009年2月26日星期四

为什么Rich Edit会使对话框的DoModal()函数失败

楼主redareca(小乐)

用Appwizard生成一个简单的Dialog based Application,在上面放
一个Rich Edit标准控件,编译执行,没有出现主对话框窗口。调试发现,当
执行m_pMainWnd.DoModal()函数时,创建窗口失败返回了-1,直接推出程序。
我能确信是由Rich Edit标准控件引起的,因为将Rich Edit控件换成Edit控件,
程序运行正常。
怀疑是哪一个连接库坏了,于是卸除Visual Studio,重装,问题依旧。
前几天编译一个有List contrl的Dialog based Application,发现
在编译的机器上能执行,在另外一台机器上却不能执行。但是通过在另外那台
机器上装了个Visual Studio,也不用再该机器上重编译程序就解决问题了。
不知道这两个问题时有什么引起的,有没有关系。

1 楼adrianx(蓝色心情)

请在CXXXApp::InitInstance()中m_pMainWnd->DoModal()前调用
AfxInitRichEdit();
你的DoModal就可以用了
另外一台机上是否没有RICHED32.DLL和OLE32.dll
和MFC的一些DLLTop

2 楼coolskeeter(文子)

对于这位兄台所说的关于Rich Edit 控件的问题,小弟碰巧也碰到过。情形是这样的,我在一个document_view 结构的程序中,要从菜单click事件中 使一个dialog .DoModal().但是该对话框并不能出现,调试时发现对话框的m_hWnd NULL。将对话框中的Rich Edit控件删除后,一切完好。最后我的解决办法是,在该dialog 的OnInitDialog() 中用程序去生成一个RichEdit, 那样可以用了,并能正确显示。
class CMyDialog
{
//.....
protected:
CRichEditCtrl m_myRichEdit;//添加一个成员变量到对话框类。
//.............
}

CMyDialog::OnInitDialog()
{
//...................
if(!m_myRichEdit.Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID ))
MessageBox("Create RichEdit fail");
//...................
}

其中,nID 我是在.h 文件中自己去
#defined IDC_RICHEDIT 128 写的。
希望能对老兄有点帮助。不过如果有简单点的办法像其他控件一样的做法的话,还望能告知小弟一声。
你说得第二个问题我想是由于动态库的问题。安装了visual Studio后自动安装了一些 DLLs 吧。
3 楼happylaodu(青菜豆腐)
同意adrianx的意见:当在你的程序中要使用CRichEditCtrl时,就必须调用AfxInitRichEdit();函数。

但coolskeeter所说的方法也可行,只不过,对于rect参数,事先得要花点脑筋算一算,最后显示出来的效果如果不满意,还得重设,有点繁。

2009年2月25日星期三

VC中如何打开指定程序或者文件

⑴ 函数原型:

UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);

⑵ 参数:

lpCmdLine:指向一个空结束的字符串,串中包含将要执行的应用程序的命令行(文件名加上可选参数)。

uCmdShow:定义Windows应用程序的窗口如何显示,并为CreateProcess函数提供STARTUPINFO参数的wShowWindow成员的值。

⑶ 返回值:

若函数调用成功,则返回值大于31。若函数调用失败,则返回值为下列之一:

① 0:系统内存或资源已耗尽。

② ERROR_BAD_FORMAT:EXE文件无效(非Win32.EXE或.EXE影像错误)。

③ ERROR_FILE_NOT_FOUND:指定的文件未找到。

④ ERROR_PATH_NOT_FOUND:指定的路径未找到。

虽然Microsoft认为WinExec已过时,但是在许多时候,简单的WinExec函数仍是运行新程序的最好方式。简单地传送作为第一个参数的 命令行,还需要决定如何显示程序(该程序也许会忽视它)的第二个参数。通常,将其设置为SW_SHOW,也可尝试SW_MINIMIZED 或 SW_MAXIMIZED。WinExec不允许用CreateProcess获得的所有选项,而它的确简单。

使用ShellExecute命令

⑴ 函数原型:

Quote:
HINSTANCE ShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);


⑵ 参数:

hwnd:指向父窗口的窗口句柄。此窗口接收应用程序产生的任何信息框。

lpOperation:一个空结束的字符串地址,此字符串指定要执行的操作。下面的操作字符串是有效的:

"open" 此函数打开由参数lpFile指定的文件,此文件可以是一个可执行文件或文档文件,也可是一个文件夹。
"print" 此函数打印由参数lpFile指定的文件,此文件应是一个文档文件,假如此文件是一个可执行文件,则打开此文件。
"explore" 此函数搜索由参数lpFile指定的文件夹,此文件应是一个文档文件,

此参数可以为空。这种情况下,函数用于打开由参数lpFile指定的文件。

lpFile:一个空结束的字符串地址,此字符串指定要打开或打印的文件或者是要打开或搜索的文件夹。

lpParameters:假如参数lpFile指定一个可执行文件,lpParameters则是一个空结束的字符串地址,此字符串指定要传递给应用程序的参数。假如lpFile指定一个文档文件,lpParameters应为空。

lpDirectory:一个空结束的字符串地址,此字符串指定默认目录。

nShowCmd:假如lpFile指定一个可执行文件,nShowCmd表明应用程序打开时如何显示。假如lpFile指定一个文档文件,nShowCmd应为空。

⑶ 返回值:

若函数调用成功,则返回值大于32,否则为一个小于等于32的错误值。

说明:可以用此函数打开或搜索一个外壳文件夹。打开文件夹可用下面任何一种形式:

Code:

ShellExecute(handle, NULL, path_to_folder, NULL, NULL, SW_SHOWNORMAL);




Quote:
ShellExecute(handle, "open", path_to_folder, NULL, NULL, SW_SHOWNORMAL);


搜索文件夹,可用如下形式

ShellExecute(handle, "explore", path_to_folder, NULL, NULL, SW_SHOWNORMAL);

ShellExecute 命令虽已过时但易于得到。该命令向命令解释程序提出打开、浏览或打印文档或文件夹的请求,虽然可以用 ShellExecute运行程序,但通常只发送文档名,而命令解释程序则决定要运行那个程序。另外在打开目录文件夹时,ShellExecute命令非 常有用。

⑷ 程序示例

下面通过一个例子来说名WinExec和ShellExecute的使用。下面程序有控制台程序示例,其使用两种不同的方法,打开文本文件。下面程序使用WinExec,并明确指定使用记事本程序。然后,使用ShellExecute,打开文本文件。

程序清单

Code:
#include
#include

void main(int argc,char *argv[])
{
cout < <”Opening with WinExec\n”;
if (WinExec(“notepad readme.txt”,SH_SHOW) <32)
MessagBox(NULL,”Can’t WinExec”,NULL,MB_OK);
cout < <”Press Enter\n”;
MessagBox(NULL,”Press OK to continue”,”Progrm Launched”,MB_OK);
cout < <”Opening with ShellExecute\n”;
if (ShellExecute (NULL,”open”,”readme.txt”,NULL,NULL,SW_SHOW) <(HANDLE) 32)
MessagBox(NULL,”Can’t ShellExecute\n”,NULL,MB_OK);
}


使用CreateProcess命令

⑴ 函数原型:

Code:
BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);


⑵ 参数:

lpApplicationName:指向一个以空结尾的串,他指定了要执行的模块

lpCommandLine:指向一个以空结尾的串,该串定义了要执行的命令行。

lpProcessAttributes:指向一个SECURITY_ATTRIBUTES结构,该结构决定了返回的句柄是否可被子进程继承。

lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构,该结构决定了返回的句柄是否可被子进程继承。

bInheritHandles,:表明新进程是否从调用进程继承句柄。

dwCreationFlags:定义控制优先类和进程创建的附加标志。

lpEnvironment:指向一个新进程的环境块。

lpCurrentDirectory:指向一个以空结尾的串,该串定义了子进程的当前驱动器和当前目录。

lpStartupInfo:指向一个STARTUPINFO结构,该结构定义了新进程的主窗口将如何显示。

lpProcessInformation:指向PROCESS_INFORMATION结构,该结构接受关于新进程的表示信息。

⑶ 返回值:

若函数调用成功,则返回值不为0;若函数调用失败,返回值为0。

ShellExecute和WinExec命令用于简单的作业。如果要完全控制一个新进程,就必须调用CreateProcess。

在上述参数中,参数lpStartupInfo是STARTUPINFO结构。可以用来设置控台的标题,新窗口的的初始大小和位置,及重定向标准输入 和输出。新程序通常可以忽略多数这些数据项,如果选择那样做的话。可以规定该结构体中的标志,已表明要设置的数据段。有时,不想设置任何信息,也必须传递 一个有效的指针给空结构(确定设置大小到cb,及设置dwFlags成员为0)。参数lpProcessInformation返回进程和线程句柄,还包 括进程和线程ID。这些句柄拥有在参数lpProcessAttributes和lpThreadAttributes中规定的访问。

要注意,针对CreateProcess的一些参数对控制台应用程序是特定的,而其它参数则对各种应用程序有用。大多数情况下,并不一定要填入 STARTUPINFO结构,但无论如何必须提供它。其返回值是布尔型的,而真正感兴趣的返回值发生于作为参数传送的结构中 (PROCESS_INFORMATION)。CreateProcess返回该结构中的进程ID及其句柄,以及初始线程ID及其句柄。可以将ID发送到 其它进程,或使用句柄来控制新进程。

如何对CTreeCtrl遍历和查找

VC 编程中,若要展现一个树形结构,我们基本都会继承CTreeCtrl进行扩展。通过InsertItem、SetItemData等操作可以建立起一颗树并展现出来。对树的操作,最常用的就是遍历和查找。如何遍历一个CTreeCtrl呢,以下是采用递归完成的遍历树的函数


遍历树
//hitem:待遍历树的根节点

void TreeVisit(HTREEITEM hItem)

{

AfxMessageBox(GetItemText(hItem));

  if(ItemHasChildren(hItem))

  {

   HTREEITEM hChildItem = GetChildItem(hItem);

   while(hChildItem!=NULL)

   {

    TreeVisit(hChildItem); //递归遍历孩子节点

     hChildItem = GetNextItem(hChildItem, TVGN_NEXT);

   }

  }

}



如何根据名称查找树中的某个节点

//item:待遍历树的根节点,strtext:待查找节点名称

HTREEITEM finditem(HTREEITEM item, CString strtext)

{

HTREEITEM hfind;



//空树,直接返回NULL

if(item == NULL)

return NULL;



//遍历查找

while(item!=NULL)

{

//当前节点即所需查找节点

if(GetItemText(item) == strtext)

return item;



//查找当前节点的子节点

if(ItemHasChildren(item))

{

item = GetChildItem(item);

//递归调用查找子节点下节点

hfind = finditem(item,strtext);

if(hfind)

{

return hfind;

}

else //子节点中未发现所需节点,继续查找兄弟节点

item = GetNextSiblingItem(GetParentItem(item));



}

else{ //若无子节点,继续查找兄弟节点

item = GetNextSiblingItem(item);

}

}



return item;

}



这两个函数均在CTreeCtrl的扩展类当中做为成员函数即可实现树的遍历和查找。

两个函数遍历的实质是相同的:先查找第一个子节点,再查找以该节点为根的子树,再逐个查找该子节点的兄弟节点,最终完成遍历。第二个函数在找到符合条件的节点时即返回,而第一个函数则访问了树的所有节点。



这两个函数均在CTreeCtrl的扩展类当中做为成员函数即可实现树的遍历和查找。

两个函数遍历的实质是相同的:先查找第一个子节点,再查找以该节点为根的子树,再逐个查找该子节点的兄弟节点,最终完成遍历。第二个函数在找到符合条件的节点时即返回,而第一个函数则访问了树的所有节点。

两个函数均在VC60环境下编译运行通过。

2009年2月19日星期四

MFC动态创建控件的消息处理

前些天有人在论坛里问在动态创建TreeCtrl后怎么响应消息,于是便写了一点自己的心得,现整理如下。

  本例在view中动态创建一个ListCtrl并响应其NM_CLICK消息,先写出动态创建的代码:

新建一SDI工程,给view加上一个成员变量:
CListCtrl m_list;
在view的OnCreate中创建它:
if(!m_list.Create(WS_BORDER |WS_CHILD|WS_VISIBLE|LVS_ICON |LVS_AUTOARRANGE|LVS_SHOWSELALWAYS|LVS_EDITLABELS,CRect(10,10,310,210),this,ID_LISTCTRL))
{
TRACE0("Failed to create ListCtrl window\n");
return -1;
}
//添加一些项
CString str;
for(int i=0;i<10;i++)>Resource Symbols弹出的对话框中点击New按钮,在Name下面输入ID_LISTCTRL.

创建完毕,编译链接后就可以运行了,但你怎么点击它都没反应,当然,因为我们还没写消息处理的代码。
   通常做法是手动写消息处理函数及消息映射,至少得三步:1,在头文件中定义消息处理函数的原型,2,在cpp中实现这个函数,3,在 BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之间写上消息映射。如果是单单处理一个消息的话那还可以忍受,消息一多的话不但 麻烦还容易出错。
  
所以我采取下面的方法:
1.打开about对话框资源,放入一个ListCtrl控件到对话框中,并将其ID设为ID_LISTCTRL.
2.Ctrl+W,把Class Name由原来的CAboutDlg改为CxxxView,在左边的Object IDS中选择ID_LISTCTRL,这时右边会出现相应的通知消息,这时就可以跟平常一样双击添加消息映射了.
嘿嘿,是不是跟在对话框里响应控件的消息一样很方便呀.
有一点需要注意,只有当打开你加入控件的那个对话框资源编辑器的时候按Ctrl+W时,Class Wizard中才会出现那个ID_LISTCTRL,还有发行时注意把对话框上的listctrl控件删掉.

2009年2月18日星期三

使用MFC开发ActiveX控件全过程

Visual C++是开发ActiveX控件的强大工具,它的特点是开发周期短、便于使用,因此它已经成为开发ActiveX控件的主要工具之一。Visual C++集成开发环境,使用了微软自己的类库MFCMFC对开发ActiveX控件提供了全面的支持,本文讲述的过程均在Visual C++ 6.0(以下简称VC中实现。

1、 创建工程:

对于使用过VC的人,可以很容易地创建一个开发ActiveX控件的工程,没有使用过VC的人,按

照下面的操作步骤,也可以很快创建一个同样的工程出来。

第一步:“File”—>New”—>(Projects)MFC ActiveX ControlWizard”,在“Project Name”中输入合适的工程名(以test为例),在“Location”中选择工程文件存放路径,然后,“OK”进入下一步;

第二步:选择你想在这个工程中生成的ActiveX控件的个数(至少一个),其余选项决定是否生成一些辅助文件,通常按照默认设置即可,“Next”进入下一步;

第三步:编辑你的工程中各个类和文件的名称,配置一些辅助选项,可以全部选择默认设置,“Finish”进入下一步;

第四步:展示向导为你的工程生成的各种配置信息,“Cancel”重新设置不满意的选项,“OK”结束工程的创建。

2、 绘制控件:

MFC将对ActiveX控件的支持封装在COleControl类中,所有ActiveX控件均从这个类

派生。绘制控件的全部操作则集中在一个虚函数中—OnDraw(),其默认实现如下:

void CTestCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)

{

// TODO: Replace the following code with your own drawing code.

pdc->FillRect(rcBounds,

CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

pdc->Ellipse(rcBounds);

}

可以看到,OnDraw()函数的默认实现是在矩形rcBounds中绘制一个椭圆,通过改写OnDraw()函数中的内容,就可以绘制自己想要的控件了。需要注意的一点,控件的绘制被限制在矩形rcBounds中,绘制范围不能超出这个矩形。

3、 添加属性:

ActiveX控件提供了三种类型的属性供用户选择:公共属性、具有通知特性的属性和Get/Set

类型的属性。下面依次对三种类型属性的添加、初始化、新属性值的获取和属性的永久保存,分别进行介绍。

三种类型的属性的添加,都遵照相同的步骤:“View”—>ClassWizard”—>(Automation)Add Property”—>Add Property”对话框。注意,“Class Name”中应是你想添加属性的控件类的名称(如CTestCtrl)。

㈠. 公共属性

COleControl类提供了九种常用的属性作为公共属性,我们以“Caption”为例。在“Add Property”对话框中的“External Name”选择“Caption”,“Implementation”中选中“Stock,然后“OK”即向控件添加了Caption公共属性。

COleControl类为每一个公共属性都提供了默认的设置和获取成员函数,对于Caption属性有SetText()GetText()(InternalGetText())

COleControl类在函数DoPropExchange()中对于公共属性都有默认的初始化,但是我们可以在成员函数OnResetState()中,为公共属性设置我们自己想要的初始值。Caption默认的初始值为空,可以使用成员函数SetText( LPCTSTR pszText ),为其设置任意的字符串。

我们可以通过调用函数GetText()InternalGetText()获得当前的Caption属性值。需要注意的是,对于GetText()函数,在调用之后,需要调用SysFreeString()函数以释放资源。此外,GetText()函数的返回值为BSTR类型,经常需要与大家常用的CString字符串类型进行变换:BSTR可以直接赋值CString,也可以调用API函数::SysAllocString(Cstring);但是将CString转换成BSTR,必须调用函数CString::AllocSysString()InternalGetText()函数则无上述烦恼。

对于公共属性的永久保存,在COleControl类的成员函数DoPropExchange()有默认实现,就无需大家费心了。

㈡. 具有通知特性的属性

在“Add Property”对话框的“Implementation”中选中“Member variable”,即选择了向控

件添加具有通知特性的属性。在“External Name”中输入属性的名字(Shape),在“Type”中选择变量类型(BOOL),“Variable Name”和“Notification function”中会自动生成默认的变量名(m_shape)和通知函数名(OnShapeChanged),当然也可以手工输入自己习惯的名字。最后,“OK”便向控件添加了一个具有通知特性的属性。

对于属性的初始化和永久保存,只要在DoPropExchange()函数中调用PX_函数即可。按照上面添加的属性例子,可以如是调用:PX_Bool(pPX, _T("Shape"), m_bShape, FALSE)。其中,“FALSE”为变量“m_bShape”即属性“Shape”的初始值。

至此,不得不先说一下控件的属性对话框了。MFC将控件的属性对话框封装在类COlePropertyPage中,所有控件的属性对话框都派生自这个类。控件的属性对话框,是控件开发者提供给控件用户、用于定制控件外观的通讯工具,控件用户可以通过它来修改控件的某些属性。COlePropertyPage类中最重要的成员当属DoDataExchange()函数了,控件开发者就是通过在其中调用DDP_函数把控件的属性与控件属性对话框中的各种控件联系起来的。对于控件的公共属性,在为属性对话框中的相应控件添加变量的时候,可以在“Optional property name”中选择相应的公共属性,则属性对话框类就会在DoDataExchange()函数种自动添加相应的DDP_函数,例如,对于Caption属性,就会自动添加这样的语句:DDP_Text(pDX, IDC_CAPTION_EDIT, m_strCaption, _T("Caption") );但是对于用户添加的自定义属性,则必须手工输入DDP_函数,例如,对于前面添加的“Shape”属性,应添加如下语句:DDP_Check(pDX, IDC_SHAPE_CHECK, m_bShape, _T("Shape") )

对于“Notification function”需要补充说明的是,虽然在相应的函数中,属性添加向导会自动添加函数SetModifiedFlag(),但是如果需要在属性被改变时,相应改变控件的显示,则需开发人员手工加入函数InvalidateControl()(它会激发OnDraw()函数的调用)

㈢. Get/Set类型的属性

在“Add Property”对话框的“Implementation”中选中“Get/Set mothods”,即选择了向控

件添加“Get/Set类型的属性”。 在“External Name”中输入属性的名字(Color),在“Type”中选择变量类型(OLE_COLOR),“Get function”和“Set function”中会自动生成默认的函数名“GetColor”和“SetColor”,当然也可以手工输入自己习惯的函数名。最后“OK”,便完成了向控件添加Get/Set类型的属性。

对于属性的初始化和永久保存,和上面“具有通知特性的属性”一样,只要在DoPropExchange()函数中调用相应的PX_函数即可,不过在此之前,需要声明一个与属性类型相同的变量(m_clrInside),用于保存属性的值。(PX_函数: PX_Color(pPX, _T("Color"), m_clrInside, RGB(255, 255, 255)),其中“RGB(255, 255, 255)”为变量“m_clrInside”即属性“Color”的初始值)

现在,需要说明一下公共属性页的问题了:在ActiveX默认的属性页中,没有字体和颜色属性页,但我们可以通过在属性页的ID表中添加入口的方法添加这两个属性页。加入颜色属性页的代码如下:

BEGIN_PROPPAGEIDS(CTest1Ctrl, 2)

PROPPAGEID(CTest1PropPage::guid)

PROPPAGEID(CLSID_CColorPropPage)

END_PROPPAGEIDS(CTest1Ctrl)

其中,以粗体显示的代码,由开发人员加入,同时ID数目增加1,由原来的1变为2

Get/Set类型的属性,属性值的获取和设置分别由相应的Get/Set函数处理。Get函数中返回当前的属性值(return m_clrInside);Set函数中设置新的属性值(m_clrInside = nNewValue),同样,如果需要在属性被改变时,改变控件的显示,需开发人员手工加入函数InvalidateControl()

4、 添加事件:

事件是AcTiveX控件通知ActiveX控件容器的手段,一般事件是由一些交互操作激发的,如鼠

标操作、键盘操作等。ActiveX控件支持公共事件和自定义事件,两者添加方法相似,只是公共事件由COleControl类自动处理。

使用VC自带的ClassWizard添加事件:“View”—>ClassWizard”—>(ActiveX Events)Add Event...”,出现“Add Event”对话框。如果是添加公共事件,只要在“External Name”下拉列表中选择想要添加的事件,“OK”即可;添加自定义事件,则在“External Name”中输入自定义事件的名称(ClickIn),“Internal Name”中会自动生成事件激发函数的名称(FireClickIn),也可以输入自己习惯的名字,然后在“Parameter list”中输入需要的参数名称(Hit)和参数类型(BOOL),最后“OK”就完成了自定义事件的添加。

对于公共事件,COleControl类会自动激发,例如:当鼠标中的任意一个键在单击控件时,Click事件就会自动被激发,向控件容器发送通知;对于自定义事件,必须由开发人员在需要激发事件的时候,调用相应的成员函数,来激发事件,以上面的“ClickIn”自定义事件为例,在需要激发事件的地方,需要开发人员调用相应的事件激发函数“FireClickIn”来激发“ClickIn”事件。附带一提,事件携带的参数是控件容器判断事件类型的依据,例如上面的“Hit”参数,其值为“TRUE”或“FALSE”,就可以代表两种不同的情形。

5、 测试控件:

完成了控件的编码工作,接下来就需要对控件进行相关的测试了。测试控件,就需要一个控件

容器来装载控件,如果只是为了测试控件,而专门开发一个控件容器,根本就是本末倒置、得不偿失,开发一个ActiveX控件容器的工作量,是绝对不容小觑的!幸运的是,VC为我们提供了一个方便的ActiveX控件测试工具—“ActiveX Control Test Container”(以下简称ACTC),这是VCActiveX控件开发人员,方便进行ActiveX控件的测试,而专门开发的一个ActiveX控件容器。

ACTC使用起来非常方面,可以通过两种方式打开它:一、在VC的主界面中,“Tools”—>ActiveX Control Test Container”;二、“Execute Program”时,在跳出的“Executable For Debug Session”对话框的“Executable file name”中选择“ActiveX Control Test Container”,然后“OK”即可。

ACTC打开之后,“Edit”—“Insert New Control”或在窗口空白处单击右键,然后选择“Insert New Control”,就会打开“Insert Control”对话框,最后在对话框左边的列表中找到自己的控件并选中,“OK”相应控件就会被添加到并显示在ACTC中。

测试控件的属性,可以“Edit”—>Properties...”,就会打开控件的属性对话框;测试事件,事件的结果会在ACTC下面的窗口中显示。

2009年2月17日星期二

ActiveX控件在IE中不能显示的解决方案

Q:

VC6生成MFC ActiveX,使用htm调用,

CLASSID="CLSID:12342234-3234-4234-5234-623472348234"

CODEBASE="testocx.cab#version=1,0,0,1"

在WinXPSp1上,http://www.smth.org/,ok

在WinXPSp2/2k3SP1/Vista上,http://www.smth.org/,红X

在WinXPSp2/2k3SP1/Vista上,file:///C:/ActiveX.htm,ok

A:

ActiveX在远程IE页面上执行,需要实现安全接口。

在ATL写的ActiveX中,用IObjectSafety。

http://support.microsoft.com/kb/168371/en-us

在MFC写的ActiveX中,直接修改注册表。

http://support.microsoft.com/kb/161873/en-us

mfc实现的ocx,要在app实现文件中包括两个文件:

atl实现的ocx,在声明文件CTestCtl.h中:

或者: