com组件中的接口,在继承的时候,是不是有什么不一样??

draculamx 2020-07-17 12:27:06
最近碰到个项目,需要用到一个com组件:xxx.dll,在给出的头文件中,有一个接口:IProgress

extern __declspec (package) const GUID IID_IProgress;

interface DECLSPEC_UUID("{C23CF58D-3121-45D2-A0DB-B19F98350D52}") IProgress;
typedef TComInterface<IProgress, &IID_IProgress> IProgressPtr;

// *********************************************************************//
// Interface: IProgress
// Flags: (4352) OleAutomation Dispatchable
// GUID: {C23CF58D-3121-45D2-A0DB-B19F98350D52}
// *********************************************************************//
interface IProgress : public IDispatch
{
public:
HRESULT STDMETHODCALLTYPE ProgressCallback(double Progress/*[in]*/); // [201]
};

// *********************************************************************//
// DispIntf: IProgress
// Flags: (4352) OleAutomation Dispatchable
// GUID: {C23CF58D-3121-45D2-A0DB-B19F98350D52}
// *********************************************************************//
template<class T>
class IProgressDispT : public TAutoDriver<IProgress>
{
public:
IProgressDispT(){}

IProgressDispT(IProgress *pintf)
{
TAutoDriver<IProgress>::Bind(pintf, false);
}

IProgressDispT(IProgressPtr pintf)
{
TAutoDriver<IProgress>::Bind(pintf, true);
}

IProgressDispT& operator=(IProgress *pintf)
{
TAutoDriver<IProgress>::Bind(pintf, false);
return *this;
}

IProgressDispT& operator=(IProgressPtr pintf)
{
TAutoDriver<IProgress>::Bind(pintf, true);
return *this;
}

HRESULT __fastcall ProgressCallback(double Progress/*[in]*/);

};
typedef IProgressDispT<IProgress> IProgressDisp;


然后我写代码的时候,用一个类继承了这个接口,并且希望把这个接口中的函数:ProgressCallback进行“实现”,因为接口中只给出了函数声明,并没有去实现它,而且接口中的这个函数,不是虚函数,没有virtual关键字。

代码大概如下:

class B;

class A:public B,public IProgress
{
public:
HRESULT STDMETHODCALLTYPE ProgressCallback(double Progress)
{
//do something();
return 0;
}
}

A a;
IProgress *p=&a;

//编译没有问题,运行没有问题
a.ProgressCallback(1);

//编译没有问题,运行到这里直接报错:pure virtual function called
//为什么要这么调用,因为有个函数的参数,类型是“IProgress *”,这个函数也是com里面的函数
p->ProgressCallback(1);



我现在想搞明白,如果要实现com里面“IProgress”接口的“ProgressCallback”方法,要怎么做呢??
在类A中的“ProgressCallback”,难道没有覆盖接口“IProgress”里面的“ProgressCallback”方法??

最后,头文件中最后出现的IProgressDispT 这个类是做什么用的?它也继承了IProgress接口
...全文
237 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
真相重于对错 2020-07-17
  • 打赏
  • 举报
回复
com 接口不是你去实现它或者说继承它,而是组件类自己实现了那个接口,接口暴露给你让你用而已。
真相重于对错 2020-07-17
  • 打赏
  • 举报
回复
com是个比较复杂的技术,它是基于二进制的复用,建议系统的学习一下,看看com本质论,深入探索atl 这两本老书
  • 打赏
  • 举报
回复
如果
A a;
IProgressDisp *p = (IProgressDisp *)&a;
Simple-Soft 2020-07-17
  • 打赏
  • 举报
回复
这个ProgressCallback一般不是自己调用的,是别的组件调用自己的回调函数。
draculamx 2020-07-17
  • 打赏
  • 举报
回复
引用 6 楼 真相重于对错 的回复:
com回调函数也叫连接点 https://blog.csdn.net/witlym311/article/details/8931697?utm_source=blogxgwz1
大佬,能不能根据我给出的这个例子,给点代码来实现com回调函数?? 你这个链接的内容我只看得懂50%。。。。
真相重于对错 2020-07-17
  • 打赏
  • 举报
回复
draculamx 2020-07-17
  • 打赏
  • 举报
回复
引用 1 楼 Simple-Soft 的回复:
这个ProgressCallback一般不是自己调用的,是别的组件调用自己的回调函数。
我这里只是想把提问简单化一点,实际上它确实是一个回调函数 我之所以说,IProgress里面的ProgressCallback是被自己的代码(com外部)实现了,是有依据的,那就是厂商给出的同样使用了这个COM组件,并且成功调用了IProgress里面的ProgressCallback函数的Delphi例子,这个例子,我编译过,运行过,没有任何问题,这个例子使用的com就是我在自己的C++代码里使用的com,保证100%是同一个dll文件。 delphi 代码如下(简化版):

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, BASSEncoder_TLB, Vcl.ComCtrls;

type
  TForm1 = class(TForm, IProgress)
    ProgressBar1: TProgressBar;
    Button7: TButton;
  
 
    procedure Button7Click(Sender: TObject);

  private
    { Private declarations }
    function ProgressCallback(Progress: Double): HResult; stdcall;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

Uses
    //BASSEncoderLibrary,
    ComObj;

procedure TForm1.Button7Click(Sender: TObject);
var
    BASSEncodeFileMP3: IBASSEncodeFile;
    Error: HResult;
begin
    //* Acquire the class
    BASSEncodeFileMP3 := CreateComObject(CLASS_TBASSEncodeFileMP3) as IBASSEncodeFile;
    //* Generate MP3, CBR 320 kbps, 44100 Hz, 2 channels (stereo)
    Error := BASSEncodeFileMP3.EncodeFile(EditInputFileName.Text, EditOutputFileName.Text, '-b 320', 44100, 2, 0, 0, 0, Self);
    if Error <> 0 then begin
        Showmessage('Error: ' + IntToStr(Error));
    end;
end;

function TForm1.ProgressCallback(Progress: Double): HResult; stdcall;
begin
    ProgressBar1.Position := Round(Progress);
    Result := S_OK;
end;

end.
虽然语言是Delphi,相信大家都看得明白,我的C++代码就是直接把这个delphi代码进行了翻译,给出关键部分,节约大家时间:

class TMainForm:public TForm,public IProgress
{
    //....
private:
    HRESULT STDMETHODCALLTYPE ProgressCallback(double Progress);
}

HRESULT TMainForm::STDMETHODCALLTYPE ProgressCallback(double Progress)
{
    return 0;
}

void __fastcall TFormMain::btn1Click(TObject *Sender)
{
    IBASSEncodeFilePtr BASSEncodeFileMP3;
    BASSEncodeFileMP3 = CreateComObject(CLSID_TBASSEncodeFileMP3);
    BASSEncodeFileMP3->EncodeFile(L"C:\\11.wav", L"C:\\22.mp3", L"-b 320", 44100, 2, 0, 0, 0, this);
}
我这个C++代码,完全就是Delphi翻译过来的,唯一不同的就是,当我执行btn1Click的时候,会弹出错误:Pure virtual function called... 我现在的想法就是,delphi和C++在调用com的过程中,存在一些差别,才导致这个结果。。

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧