问题描述
我有ATL编程的初学者.
我按照Inside ATL书中的建议创建了一个示例程序TipServer.但是在运行程序时会给出运行时错误
实际上找不到组件提供的接口.
我的clint程序也使用VC ++,并且我已正确注册了我的组件.
请参阅下面的客户端代码.并请让我知道我在哪里做错.
//------------
//TipDlg.cpp
//------------
#include"stdafx.h" #include"resource.h"
//CG:此文件是由每日提示"组件添加的.
#include< winreg.h>
#include< sys \ stat.h>
#include< sys \ types.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
静态字符THIS_FILE [] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////////////
//CTipDlg对话框
#define MAX_BUFLEN 1000
静态常量TCHAR szSection [] = _T("Tip");
静态const TCHAR szIntFilePos [] = _T("FilePos");
静态const TCHAR szTimeStamp [] = _T("TimeStamp");
静态常量TCHAR szIntStartup [] = _T("StartUp");
静态const TCHAR szCookie [] = _T("Cookie");
CTipDlg :: CTipDlg(CWnd * pParent/* = NULL */)
:CDialog(IDD_TIP,pParent)
{
//{{AFX_DATA_INIT(CTipDlg)
m_bStartup = TRUE;
//}} AFX_DATA_INIT
//我们需要找出启动和文件位置参数是什么
//如果启动不存在,则假定启动提示被选中为TRUE.
CWinApp * pApp = AfxGetApp();
m_bStartup =!pApp-> GetProfileInt(szSection,szIntStartup,0);
vtCookie =(long)pApp-> GetProfileInt(szSection,szCookie,0);
HRESULT hResult =
m_tipOfDay.CreateInstance("TipServer.TipOfTheDay");
if(SUCCEEDED(hResult))
GetNextTipString(m_strTip);
}
CTipDlg ::〜CTipDlg()
{
//无论用户是否按下退出键,都会执行此析构函数
//或单击关闭按钮.如果用户按下了退出键,
//仍然需要使用
更新ini文件中的filepos//最新职位,以便我们不再赘述!
//但是请确保提示文件首先存在....
CWinApp * pApp = AfxGetApp();
:: VariantChangeType(& vtCookie,& vtCookie,0,VT_I4);
pApp-> WriteProfileInt(szSection,szCookie,vtCookie.lVal);
}
无效CTipDlg :: DoDataExchange(CDataExchange * pDX)
{
CDialog :: DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTipDlg)
DDX_Check(pDX,IDC_STARTUP,m_bStartup);
DDX_Text(pDX,IDC_TIPSTRING,m_strTip);
//}} AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTipDlg,CDialog)
//{{AFX_MSG_MAP(CTipDlg)
ON_BN_CLICKED(IDC_NEXTTIP,OnNextTip)
ON_WM_CTLCOLOR()
ON_WM_PAINT()
//}} AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//CTipDlg消息处理程序
无效CTipDlg :: OnNextTip()
{
GetNextTipString(m_strTip);
UpdateData(FALSE);
}
无效CTipDlg :: GetNextTipString(CString& strNext)
{
strNext =(BSTR)(m_tipOfDay-> GetNextTip(& vtCookie));
}
HBRUSH CTipDlg :: OnCtlColor(CDC * pDC,CWnd * pWnd,UINT nCtlColor)
{
如果(pWnd-> GetDlgCtrlID()== IDC_TIPSTRING)
return(HBRUSH)GetStockObject(WHITE_BRUSH);
返回CDialog :: OnCtlColor(pDC,pWnd,nCtlColor);
}
无效CTipDlg :: OnOK()
{
CDialog :: OnOK();
//更新存储在INI文件中的启动信息
CWinApp * pApp = AfxGetApp();
pApp-> WriteProfileInt(szSection,szIntStartup,!m_bStartup);
}
BOOL CTipDlg :: OnInitDialog()
{
CDialog :: OnInitDialog();
//如果提示文件不存在,则禁用NextTip
如果(m_pStream == NULL)
GetDlgItem(IDC_NEXTTIP)-> EnableWindow(FALSE);
返回TRUE; //返回TRUE,除非将焦点设置为控件
}
无效CTipDlg :: OnPaint()
{
CPaintDC dc(this); //绘画的设备上下文
//获取较大的静态控件的绘制区域
CWnd * pStatic = GetDlgItem(IDC_BULB);
CRect rect;
pStatic-> GetWindowRect(& rect);
ScreenToClient(& rect);
//将背景涂成白色.
CBrush brush;
brush.CreateStockObject(WHITE_BRUSH);
dc.FillRect(rect,& brush);
//加载位图并获取位图的尺寸
CBitmap bmp;
bmp.LoadBitmap(IDB_LIGHTBULB);
BITMAP bmpInfo;
bmp.GetBitmap(& bmpInfo);
//在顶角绘制位图,仅验证窗口的顶部
CDC dcTmp;
dcTmp.CreateCompatibleDC(& dc);
dcTmp.SelectObject(& bmp);
rect.bottom = bmpInfo.bmHeight + rect.top;
dc.BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),
& dcTmp,0,0,SRCCOPY);
//在位图旁边绘制您知道吗..."消息
CString strMessage;
strMessage.LoadString(CG_IDS_DIDYOUKNOW);
rect.left + = bmpInfo.bmWidth;
dc.DrawText(strMessage,rect,DT_VCENTER | DT_SINGLELINE);
//不要调用CDialog :: OnPaint()来绘制消息
}
//---------
//TipDlg.h
//---------
#if!defined(TIPDLG_H_INCLUDED_)
#define TIPDLG_H_INCLUDED_
//CG:此文件是由每日提示"组件添加的.
/////////////////////////////////////////////////////////////////////////////
//CTipDlg对话框
#import"../TipServer/TipServer.tlb" no_namespace
类CTipDlg:公共CDialog
{
受保护的:
variant_t vtCookie;
ITipOfTheDayPtr m_tipOfDay;
//施工
公众:
CTipDlg(CWnd * pParent = NULL); //标准构造函数
//对话数据
//{{AFX_DATA(CTipDlg)
//枚举{IDD = IDD_TIP};
BOOL m_bStartup;
CString m_strTip;
//}} AFX_DATA
FILE * m_pStream;
//覆盖
//ClassWizard生成的虚函数覆盖
//{{AFX_VIRTUAL(CTipDlg)
受保护的:
虚拟void DoDataExchange(CDataExchange * pDX); //DDX/DDV支持
//}} AFX_VIRTUAL
//实现
公众:
虚拟〜CTipDlg();
受保护的:
//生成的消息映射函数
//{{AFX_MSG(CTipDlg)
afx_msg void OnNextTip();
afx_msg HBRUSH OnCtlColor(CDC * pDC,CWnd * pWnd,UINT nCtlColor);
虚拟void OnOK();
虚拟BOOL OnInitDialog();
afx_msg void OnPaint();
//}} AFX_MSG
DECLARE_MESSAGE_MAP()
无效GetNextTipString(CString& strNext);
};
#endif//!defined(TIPDLG_H_INCLUDED_)
注意:TipDlg.h具有类定义和接口导入
感谢您的帮助和快速响应,但我仍然没有得到答案
根据您的建议,我已经检查了注册表,并在注册表中
"TipServer.TipOfTheDay"字符串可用
有关调试程序后的更多信息,我得到了空指针
当我如下调用组件API时用于接口
strNext =(BSTR)(m_tipOfDay-> GetNextTip(& vtCookie));
我的组件代码如下所示
i have beginners on ATL programming.
i created a example program TipServer as per suggested in Inside ATL book. but while running my program its give runtime error
actually its not finding interface provided by component.
my clint program is also in VC++ and i am properlly registered my component.
please see the client code below. and please let me know where i am doing mistake.
//-----------
//TipDlg.cpp
//-----------
#include "stdafx.h"#include "resource.h"
// CG: This file added by ''Tip of the Day'' component.
#include <winreg.h>
#include <sys\stat.h>
#include <sys\types.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTipDlg dialog
#define MAX_BUFLEN 1000
static const TCHAR szSection[] = _T("Tip");
static const TCHAR szIntFilePos[] = _T("FilePos");
static const TCHAR szTimeStamp[] = _T("TimeStamp");
static const TCHAR szIntStartup[] = _T("StartUp");
static const TCHAR szCookie[] = _T("Cookie");
CTipDlg::CTipDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_TIP, pParent)
{
//{{AFX_DATA_INIT(CTipDlg)
m_bStartup = TRUE;
//}}AFX_DATA_INIT
// We need to find out what the startup and file position parameters are
// If startup does not exist, we assume that the Tips on startup is checked TRUE.
CWinApp* pApp = AfxGetApp();
m_bStartup = !pApp->GetProfileInt(szSection, szIntStartup, 0);
vtCookie = (long)pApp->GetProfileInt(szSection, szCookie, 0);
HRESULT hResult =
m_tipOfDay.CreateInstance("TipServer.TipOfTheDay");
if(SUCCEEDED(hResult))
GetNextTipString(m_strTip);
}
CTipDlg::~CTipDlg()
{
// This destructor is executed whether the user had pressed the escape key
// or clicked on the close button. If the user had pressed the escape key,
// it is still required to update the filepos in the ini file with the
// latest position so that we don''t repeat the tips!
// But make sure the tips file existed in the first place....
CWinApp* pApp = AfxGetApp();
::VariantChangeType(&vtCookie, &vtCookie, 0, VT_I4);
pApp->WriteProfileInt(szSection, szCookie, vtCookie.lVal);
}
void CTipDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTipDlg)
DDX_Check(pDX, IDC_STARTUP, m_bStartup);
DDX_Text(pDX, IDC_TIPSTRING, m_strTip);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTipDlg, CDialog)
//{{AFX_MSG_MAP(CTipDlg)
ON_BN_CLICKED(IDC_NEXTTIP, OnNextTip)
ON_WM_CTLCOLOR()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTipDlg message handlers
void CTipDlg::OnNextTip()
{
GetNextTipString(m_strTip);
UpdateData(FALSE);
}
void CTipDlg::GetNextTipString(CString& strNext)
{
strNext = (BSTR)(m_tipOfDay->GetNextTip(&vtCookie));
}
HBRUSH CTipDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (pWnd->GetDlgCtrlID() == IDC_TIPSTRING)
return (HBRUSH)GetStockObject(WHITE_BRUSH);
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
void CTipDlg::OnOK()
{
CDialog::OnOK();
// Update the startup information stored in the INI file
CWinApp* pApp = AfxGetApp();
pApp->WriteProfileInt(szSection, szIntStartup, !m_bStartup);
}
BOOL CTipDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// If Tips file does not exist then disable NextTip
if (m_pStream == NULL)
GetDlgItem(IDC_NEXTTIP)->EnableWindow(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
void CTipDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// Get paint area for the big static control
CWnd* pStatic = GetDlgItem(IDC_BULB);
CRect rect;
pStatic->GetWindowRect(&rect);
ScreenToClient(&rect);
// Paint the background white.
CBrush brush;
brush.CreateStockObject(WHITE_BRUSH);
dc.FillRect(rect, &brush);
// Load bitmap and get dimensions of the bitmap
CBitmap bmp;
bmp.LoadBitmap(IDB_LIGHTBULB);
BITMAP bmpInfo;
bmp.GetBitmap(&bmpInfo);
// Draw bitmap in top corner and validate only top portion of window
CDC dcTmp;
dcTmp.CreateCompatibleDC(&dc);
dcTmp.SelectObject(&bmp);
rect.bottom = bmpInfo.bmHeight + rect.top;
dc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
&dcTmp, 0, 0, SRCCOPY);
// Draw out "Did you know..." message next to the bitmap
CString strMessage;
strMessage.LoadString(CG_IDS_DIDYOUKNOW);
rect.left += bmpInfo.bmWidth;
dc.DrawText(strMessage, rect, DT_VCENTER | DT_SINGLELINE);
// Do not call CDialog::OnPaint() for painting messages
}
//---------
//TipDlg.h
//---------
#if !defined(TIPDLG_H_INCLUDED_)
#define TIPDLG_H_INCLUDED_
// CG: This file added by ''Tip of the Day'' component.
/////////////////////////////////////////////////////////////////////////////
// CTipDlg dialog
#import "../TipServer/TipServer.tlb" no_namespace
class CTipDlg : public CDialog
{
protected:
variant_t vtCookie;
ITipOfTheDayPtr m_tipOfDay;
// Construction
public:
CTipDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CTipDlg)
// enum { IDD = IDD_TIP };
BOOLm_bStartup;
CStringm_strTip;
//}}AFX_DATA
FILE* m_pStream;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CTipDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CTipDlg();
protected:
// Generated message map functions
//{{AFX_MSG(CTipDlg)
afx_msg void OnNextTip();
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
virtual void OnOK();
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
void GetNextTipString(CString& strNext);
};
#endif // !defined(TIPDLG_H_INCLUDED_)
Note: TipDlg.h is having class defination and interface import
Thanks for the help and quick responce but still i didnt get the answer
as per your suggestion i already checked registry and in registry the
"TipServer.TipOfTheDay" string is availble
for more information after debuging the program i am getting null pointer
for interface when i call my component API as below
strNext = (BSTR)(m_tipOfDay->GetNextTip(&vtCookie));
my component code is shown below
// TipOfTheDay.h : Declaration of the CTipOfTheDay
#ifndef __TIPOFTHEDAY_H_
#define __TIPOFTHEDAY_H_
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CTipOfTheDay
class ATL_NO_VTABLE CTipOfTheDay :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CTipOfTheDay, &CLSID_TipOfTheDay>,
public IDispatchImpl<ITipOfTheDay, &IID_ITipOfTheDay, &LIBID_TIPSERVERLib>
{
public:
CTipOfTheDay()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_TIPOFTHEDAY)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CTipOfTheDay)
COM_INTERFACE_ENTRY(ITipOfTheDay)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// ITipOfTheDay
public:
STDMETHOD(GetNextTip)(/*[in, out]*/ VARIANT* pvCookie, /*[out,retval]*/ BSTR* pbstrText);
};
#endif //__TIPOFTHEDAY_H_
//------------------
//TipOfTheDay.cpp:CTipOfTheDay的实现
#include"stdafx.h"
#include"TipServer.h"
#include"TipOfTheDay.h"
/////////////////////////////////////////////////////////////////////////////
//CTipOfTheDay
#define TIP_COUNT 7
静态LPWSTR gTipText [TIP_COUNT] =
{
L你应该避免陌生人",
L好人来等待",
L放下代码;您的爱情生活很痛苦",
L今天好转",
L赢了,输了",
L"COM是爱吗?",
L所有人在爱情和战争中的公平"
};
STDMETHODIMP CTipOfTheDay :: GetNextTip(VARIANT * pvCookie,BSTR * pbstrText)
{
if(!pvCookie ||!pbstrText)
返回E_POINTER;
:: VariantChangeType(pvCookie,pvCookie,0,VT_I4);
if(pvCookie-> lVal< 0 || pvCookie-> lVal> = TIP_COUNT)
返回E_INVALIDARG;
* pbstrText = SysAllocString(gTipText [pvCookie-> lVal]);
if(++(pvCookie-> lVal)== TIP_COUNT)
pvCookie-> lVal = 0;
返回S_OK;
}
我已经调试了.
CreateInstance定义由VC98 \ Include \ COMIP.H文件提供.如下图所示
HRESULT CreateInstance(LPCSTR clsidStringA,IUnknown * pOuter = NULL,DWORD dwClsContext = CLSCTX_ALL)throw()
{
如果(clsidStringA == NULL){
返回E_INVALIDARG;
}
int大小= lstrlenA(clsidStringA)+1;
LPOLESTR clsidStringW = static_cast< LPOLESTR>(_ alloca(size * 2));
clsidStringW [0] =``\ 0'';
if(MultiByteToWideChar(CP_ACP,0,clsidStringA,-1,clsidStringW,size)== 0){
返回HRESULT_FROM_WIN32(GetLastError());
}
返回CreateInstance(clsidStringW,pOuter,dwClsContext);
}
CreateInstance函数在内部调用CoCreateInstance,如下所示.
hr = CoCreateInstance(rclsid,pOuter,dwClsContext,__ uuidof(IUnknown),reinterpret_cast< void **>(& pIUnknown));
在这里,我获取了正确的类ID(即rclsid),但是该函数无法获取该类的实例,这就是为什么它不调用QueryInterface并且我没有得到接口指针的原因.但是问题是为什么我没有得到实例?
可能是我在犯一些愚蠢的错误.
再次感谢您的帮助;)
-----------------
CoCreateInstance返回的hr = 0x800401F0(尚未调用CoInitialize.)
//------------------
// TipOfTheDay.cpp : Implementation of CTipOfTheDay
#include "stdafx.h"
#include "TipServer.h"
#include "TipOfTheDay.h"
/////////////////////////////////////////////////////////////////////////////
// CTipOfTheDay
#define TIP_COUNT 7
static LPWSTR gTipText[TIP_COUNT] =
{
L"You should avoid strangers",
L"Good things come to those who wait",
L"Lay off the code; your love life is hurting",
L"Do a good turn today",
L"You win some, you lose some",
L"COM is love?",
L"All''s fair in love and war"
};
STDMETHODIMP CTipOfTheDay::GetNextTip(VARIANT *pvCookie, BSTR * pbstrText)
{
if(!pvCookie || !pbstrText)
return E_POINTER;
::VariantChangeType(pvCookie, pvCookie, 0, VT_I4);
if(pvCookie->lVal < 0 || pvCookie->lVal >= TIP_COUNT)
return E_INVALIDARG;
*pbstrText = SysAllocString(gTipText[pvCookie->lVal]);
if(++(pvCookie->lVal) == TIP_COUNT)
pvCookie->lVal = 0;
return S_OK;
}
Hi,
I have debuged it.
CreateInstance defination is provided by VC98\Include\COMIP.H file
looks like below
HRESULT CreateInstance(LPCSTR clsidStringA, IUnknown* pOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
{
if (clsidStringA == NULL) {
return E_INVALIDARG;
}
int size = lstrlenA(clsidStringA) + 1;
LPOLESTR clsidStringW = static_cast<LPOLESTR>(_alloca(size * 2));
clsidStringW[0] = ''\0'';
if (MultiByteToWideChar(CP_ACP, 0, clsidStringA, -1, clsidStringW, size) == 0) {
return HRESULT_FROM_WIN32(GetLastError());
}
return CreateInstance(clsidStringW, pOuter, dwClsContext);
}
CreateInstance function internally calling CoCreateInstance as shown below.
hr = CoCreateInstance(rclsid, pOuter, dwClsContext, __uuidof(IUnknown), reinterpret_cast<void**>(&pIUnknown));
here i am getting correct class ID (i.e. rclsid) but the function is failed to get the instance of class that why its not calling QueryInterface and i am not getting the interface pointer.
but issue is why i am not getting the instance?
may be i am doing some silly mistake.
Thanks again for help ;)
-----------------
CoCreateInstance returned hr = 0x800401F0 (CoInitialize has not been called. )
推荐答案
这篇关于创建第一个ATL程序时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!