Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
    Call PropBag.WriteProperty("BackColor", UserControl.BackColor, vbButtonFace)
End SubPrivate Sub UserControl_ReadProperties(PropBag As PropertyBag)
    UserControl.BackColor = PropBag.ReadProperty("BackColor", vbButtonFace)
End Sub以上是VB里做ActiveX控件后保存属性用的,怎么转成DELPHI?
我的QQ 27667431,大家可以来讨论一下

解决方案 »

  1.   

    调用过程
    调用过程有诸多技巧,它们与过程的类型、位置以及在应用程序中的使用方式有关。下面的章节说明如何调用 Sub 过程和 Function 过程。调用 Sub 过程
    与 Sub 过程不同,在表达式中,Sub 过程不能用其名字调用。调用 Sub 过程的是一个独立的语句。Sub 过程还有一点与函数不一样,它不会用名字返回一个值。但是,与 Function过程一样,Sub 过程也可以修改传递给它们的任何变量的值。调用 Sub 过程有两种方法:'以下两个语句都调用了名为 MyProc 的 Sub 过程。
    Call MyProc (FirstArgument, SecondArgument)
    MyProc FirstArgument, SecondArgument注意,当使用 Call 语法时,参数必须在括号内。若省略 Call 关键字,则也必须省略参数两边的括号。调用函数过程
    通常,调用自行编写的函数过程的方法和调用 Visual Basic 内部函数过程(例如 Abs)的方法一样;即在表达式中写上它的名字。'下面的语句都调用函数 ToDec。
    Print 10 * ToDec
    X = ToDec
    If ToDec = 10 Then Debug.Print "Out of Range"
    X = AnotherFunction ( 10 * ToDec)就像调用 Sub 过程那样,也能调用函数。下面的语句都调用同一个函数:Call Year (Now)
    Year Now当用这种方法调用函数时,Visual Basic 放弃返回值。调用其它模块中的过程
    在工程中的任何地方都能调用其它模块中的公用过程。可能需要指定这样的模块,它包含正在调用的过程。调用其它模块中的过程的各种技巧,取决于该过程是在窗体模块中、类模块中还是标准模块中。窗体中的过程
    所有窗体模块的外部调用必须指向包含此过程的窗体模块。如果在窗体模块 Form1 中包含 SomeSub 过程,则可使用下面的语句调用 Form1 中的过程:Call Form1.SomeSub(arguments)
    类模块中的过程
    与窗体中调用过程类似,在类模块中调用过程要调用与过程一致并且指向类实例的变量。例如,DemoClass 是类 Class1 的实例:Dim DemoClass as New Class1
    DemoClass.SomeSub但是不同于窗体的是,在引用一个类的实例时,不能用类名作限定符。必须首先声明类的实例为对象变量(在这个例子中是 DemoClass )并用变量名引用它。详细信息 可在“用对象编程”中找到关于对象变量和类模块的详细信息。标准模块中的过程
    如果过程名是唯一的,则不必在调用时加模块名。无论是在模块内,还是在模块外调用,结果总会引用这个唯一过程。如果过程仅出现在一个地方,这个过程就是唯一的。如果两个以上的模块都包含同名的过程,那就有必要用模块名来限定了。在同一模块内调用一个公共过程就会运行该模块内的过程。例如,对于 Module1 和 Module2 中名为 CommonName 的过程,从 Module2 中调用 CommonName 则运行 Module2 中的 CommonName 过程,而不是 Module1 中的 CommonName 过程。从其它模块调用公共过程名时必须指定那个模块。例如,若在 Module1 中调用 Module2 中的 CommonName 过程,要用下面的语句:Module2.CommonName (arguments)
      

  2.   

    to :  beyondtkl(大龙驹<*爱情递归 堆栈溢出&&两湖两广两河山*>) 
       你说的好象跟我想知道的没什么关系吧,我的问题中的那两段代码可以让word保存这个ocx的属性,但在delphi里怎么实现这个功能?
      

  3.   

    call不是关键,关键是PropertyBag,  WriteProperty,  ReadProperty
      

  4.   

    PropertyBag 对象
                PropertyBag 对象包含跨越对象调用时需要保存和恢复的信息。说明通过 ReadProperties 事件和 WriteProperties 事件,可将 PropertyBag 对象传送到对象中来保存和恢复对象的状态。使用 PropertyBag 对象的方法,对象能够读写自身的属性。PropertyBag 对象的 ReadProperty 方法用来读取属性值,而 PropertyBag 对象的 WriteProperty 方法用来写属性值。属性值本身可以是一个对象;在这种情况下 PropertyBag 对象将试图保存它。////////////////////////////
    保持 ActiveX 文档数据
    数据持久性是部件存储和获取数据的能力。ActiveX 文档怎样保持数据,很大程度上依赖于显示文档的容器应用程序。某些应用程序允许把数据写到它的一个接口中来保持数据。例如,Internet Explorer 3.0(和更高的版本)和 Microsoft Office Binder 允许使用 PropertyBag 把数据写到一个文件中。但是,其它应用程序并不提供类似的存储数据的内部方法,在那些情况下,必须使用其它方法,如把数据写到文件中。首先介绍 PropertyBag。PropertyBag
    PropertyBag 对象允许把数据保存到文件中。该文件可以是 .vbd、.obd,或其它类型的文件─ 这取决于应用程序。PropertyBag 有两个方法:WriteProperty 方法和 ReadProperty 方法。PropertyBag 对象出现在 WriteProperties 和 ReadProperties 事件的声明部分。用 WriteProperty 方法保存数据
    保存数据的过程如下: 属性改变而引发的事件中调用 PropertyChanged 方法。该方法通知容器某一属性已经发生了改变。
    由于 PropertyChanged 方法,容器被“弄乱”。在容器终止以前,将发生 WriteProperties 事件。
    在 WriteProperties 事件中,用 WriteProperty 方法保存属性到 .vbd 文件。 
    下列代码给出了该过程的一个简单实例:Private Sub Text1_Change()
       PropertyChanged "Text" '通知容器某一属性已经改变。
    End SubPrivate Sub UserDocument_WriteProperties _
       (PropBag As VB.PropertyBag)
       '把属性写到属性包中。
       UserDocument.WriteProperty "Text1", Text1.Text, _
          "Hello"
    End Sub读取属性
    下次打开 ActiveX 文档,将发生 ReadProperties 事件。在该事件中,PropertyBag 可用,可使用 ReadProperty 方法检索保持的数据。下面的代码检索前面的代码存储的数据:Private Sub UserDocument_ReadProperties _
       (PropBag As VB.PropertyBag)
       '把属性读回到 TextBox 控件中。
       Text1.Text = ReadProperty("Text1", "Hello")
    End Sub保存缺省值
    可能会注意到在两段代码中,ReadProperty 都包含了一个额外的参数:缺省值 "Hello"。为何在保存属性值时要提供一个缺省值呢?保存之前,WriteProperty 方法把属性值与缺省值比较。如果相同,则没有必要保存该属性值,因为在重新加载控件时缺省值将被自动设置。这样就可避免许多的缺省项把数据文件弄得杂乱无章。保存二进制数据
    也可以将二进制数据写到 PropertyBag 或从 PropertyBag 读取二进制数据。如果要以二进制形式存储数据,那么这很有帮助。例如,以自定义格式存储的图形文件。保存二进制数据的过程与保存控件属性的过程稍有不同: 声明模块级字节数组。
    在相应的事件中,使用 ReDim 语句,并在该数组中存储二进制数据。
    调用 PropertyChanged 方法。
    在 WriteProperties 事件中,用 WriteProperty 方法保存字节数组。 
    下面的简单实现显示了这些步骤:Private mbytMyData() As Byte '声明字节数组。Private Sub cmdSavePic_Click()
       ReDim mbytMyData(1 to 5000)
       '移动数据到字节数组的代码没有给出。
       PropertyChanged
    End SubPrivate Sub UserDocument_WriteProperties(PropBag As _
       VB.PropertyBag)
       PropBag.WriteProperties "myPic", mbytMyData
    End Sub用 Open 语句保持数据
    如果正使用的容器不支持 PropertyBag,或者正在保存 User Designed Type (UDT) 数据,使用 Open 语句来从磁盘读取数据和写数据到磁盘。关于使用 Open 语句的介绍,可以在《Visual Basic 程序员指南》的“处理驱动器、文件夹和文件”中的“使用顺序文件访问”中找到。详细信息 要获得添加属性到部件应遵循的行为规范,请参阅“部件设计的一般准则”中的“给类添加属性和方法”。
      

  5.   

    //////////////////////////////
    部件数据的持久保持
    大多数的部件都有若干属性;通常,在类的 Initialize 事件中需要为这些属性建立缺省值。在对部件进行编译的时候,这些缺省值被“冻结”起来,那么,怎样才能允许使用这些部件的开发者改变这些缺省值,以便满足他们各自的特殊需要呢?为了解决这个问题,类提供了一个特殊的属性 Persistable,它可以用来保存同一个部件的不同实例的值。假设现在有一个用于贷款计算的 ActiveX DLL,其中提供了一个与计算有关的 InterestRate 属性。在初始化 InterestRate 的时候可以将其设置成某个值,但是,由于利率不可避免地要发生波动,因此在每次运行部件的时候可能需要对 InterestRate 属性进行修改。利用类的持久保持功能,InterestRate 的数值将被保存起来,只有当利率发生变化的时候才对其进行修改。每次运行部件的时候,部件可以取出存储的 InterestRate,因此部件总是能够提供最近期的利率。尽管 ActiveX 控件总是能够使它们的数据成为持久保存的;ActiveX 部件的数据的持久保存特性略有不同。控件将其属性设置值保存在它的 .cls 文件,但是部件不能够这样处理。部件使用的是一个 PropertyBag 对象,该对象能够被保存在任何地方,如文件、数据库、电子数据表格中的单元格,甚至系统注册表中。 详细信息   如果需要了解与 ActiveX 控件持久保存有关的更多信息, 请参阅“建立 ActiveX 控件”中的“保存控件属性”。设置类的持久保存
    要成为一个具有持久保存特性的类,它必须满足两个条件:它必须是公有的,而且必须是可创建的。仔细考虑一下就会明白,这些条件是有意义的,因为持久保存对私有的部件是没有必要的。如果一个类满足了这两个条件,那么“属性”窗口中将出现 Persistable 属性。在缺省情况下,Persistable 属性被设置为 0 (NotPersistable)。如果将该值设置为 1 (Persistable),三个新的事件将被加到类中:ReadProperties、WriteProperties 和 InitProperties。显然,这些事件被用于读、写和初始化类的属性。使属性成为持久保存的
    通过在 Property Let 或 Property Set 过程中实现 PropertyChanged,可以将一个属性标记为持久保存的,如下面的例子所示:Private mInterestRate As Single
    Public Property Let InterestRate(newRate As Single)
       mInterestRate = newRate
       PropertyChanged "InterestRate"
    End Sub通过调用 PropertyChanged 方法,InterestRate 属性被标记为无用的。如果类中的某个属性被调用了 PropertyChanged,那么在类终止运行的时候 WriteProperties 事件将被触发。ReadProperties、WriteProperties 和 InitProperties 事件
    当一个类终止向一个称为 PropertyBag 对象的私有存储区域写入当前属性值时,WriteProperties 事件过程被使用下列代码将一个属性保存在内部的 PropertyBag 中:Private Sub Class_WriteProperties(PropBag As PropertyBag)
       PropBag.WriteProperty "InterestRate", mInterestRate, conDefaultRate
    End Sub在上面代码中,Property Bag 的 WriteProperty 方法有三个参数:需要保存的属性的名称 ("InterestRate")、需要保存的值 (mInterestRate)、以及一个缺省值 (DefaultRate)。如果新的值与常数 conDefaultRate 一致,那么 WriteProperty 方法可以不把新值写出。ReadProperties 事件在进行类初始化的时候被触发,而且只有当 PropertyBag 中有数据的时候才被触发。如果 PropertyBag 是空的,那么触发的将是 InitProperties 事件。ReadProperties 和 InitProperties 事件中的代码被用于设置初始的属性值:Private Sub Class_ReadProperties(PropBag As PropertyBag)
       mInterestRate = PropBag.ReadProperty("InterestRate", conDefaultRate)
    End Sub
    Private Sub Class_InitProperties ()
       mInterestRate = conDefaultRate
    End Sub需要注意的是,常数 conDefaultRate 被用于上面两个过程中,以提供缺省值。使用常数来提供缺省值是值得推荐的,因为它可以避免由于在不同过程中定义不同的缺省值而导致的危险。在第一次使用 New 关键字创建 Load 类的实例时,InitProperties 事件将被触发;在类成为持久保存的之后,再次创建类的时候触发的将是 ReadProperties 事件。使用 PropertyBag 对象使对象成为持久保存的
    为了使 ActiveX 部件成为持久性的,需要创建 PropertyBag 对象的一个实例。这看起来可能有些多余,类不是已经有了自己的 PropertyBag 吗?为什么不能使用那个 PropertyBag 呢?原因很简单,当对象的生命周期结束的时候,它的 PropertyBag 也将消失。它只存在于内存中;为了保证持久保存,需要在某个合适的位置保存该对象的一份副本,以便在将来需要的时候能够再次将其取出。PropertyBag 可以被看作一个“大麻袋”,它可以被装满东西,然后藏在某个安全的地方。到底藏在什么地方将完全取决于实现者。下面的窗体代码演示了如何使一个对象持久性地保存在一个文本文件中:Private pb As PropertyBag      ' 声明一个 PropertyBag 对象。
    Private LoanObject As Loan      ' 声明一个 Loan 对象。Private Sub Form_Unload(Cancel As Integer)
       Dim varTemp as Variant   ' PropertyBag 对象的实例化。
       Set pb = New PropertyBag
       ' 使用 WriteProperty 将对象保存在 PropertyBag 中。
       pb.WriteProperty "MyLoanObject", LoanObject
       ' 将 PropertyBag 的内容赋予一个 Variant。
       varTemp = pb.Contents
       ' 将其保存到一个文本文件中。
       Open "C:\Loandata.txt" For Binary As #1
       Put #1, , varTemp
       Close #1
    End SubPropertyBag 对象的 Contents 属性中包含了以字节数组形式保存的 Loan 对象。为了将其保存到一个文本文件,必须首先将其转换成一种文本文件可以理解的数据类型,例如本例中的 Variant。利用保存的数据恢复一个对象
    当对象已经被保存在文本文件中之后(或者其他类型的存储空间中),它可以被方便地转移到其他位置。请想象 Loan 对象中不仅包含了 InterestRate,还包含了贷款应用程序中所需的其他所有属性值。那么 Loandata.txt 文件可以被递交到中心部门进行验证。如果窗体需要再次使用 Loan 对象,那么代码将类似于下面的样子:Private pb As PropertyBag      ' 声明一个 PropertyBag 对象。
    Private LoanObject As Loan      ' 声明一个 Loan 对象。Private Sub Form_Load()
       Dim varTemp As Variant
       Dim byteArr() as Byte   ' PropertyBag 对象的实例化。
       Set pb = New PropertyBag
       ' 将文件的内容读入一个 Variant 中。
       Open "C:\Loandata.txt" For Binary As #1
       Get #1, , varTemp
       Close #1
       ' 将 Variant 赋值到一个 Byte 数组中。
       ByteArr = varTemp
       ' 赋予 PropertyBag Contents 属性。
       Pb.Contents  = ByteArr
       ' 使用 PropertyBag 进行对象实例化。
       Set LoanObject = pb.ReadProperty("MyLoanObject")
    End If有人可能已经注意到,对象需要被赋值三次:首先从文本文件到 Variant,然后从 Variant 到 Byte 数组,最后才赋值到 Contents 属性。这是因为,Contents 属性只能接受 Byte 数组,如果试图将其他数据类型赋予它,得到的将是一条错误信息。那么,到底发生了什么呢?我们是否真的在甲地创建了一个对象,而在乙地重新使用它呢(完全保持了它的数据)?其实,不完全是这样的。实际上,原始的对象已经被消灭了,我们在 PropertyBag 中实际传递的其实只是对象的一份精确副本,而不是对象本身。这种“克隆”一个对象以便进行复用的能力是一种功能非常强大的概念,它对于工作流应用程序的设计尤为重要。////////////////
    給你一些資料 我沒做過這方面的。。我不要分呵呵 看樓主的名字不錯。。
      

  6.   

    分是一定要给点的,可惜不适合delphi,delphi里没PropertyBag 可用,做不了
      

  7.   

    经过一晚上的努力,在delphi中找到了PropBag,但还是无法保存,真失败
      

  8.   

    function IPersistPropertyBag.Load = PersistPropertyBagLoad;
        function IPersistPropertyBag.Save = PersistPropertyBagSave;    function PersistPropertyBagLoad(const pPropBag: IPropertyBag;
          const pErrorLog: IErrorLog): HResult; stdcall;
        function PersistPropertyBagSave(const pPropBag: IPropertyBag; fClearDirty: BOOL;
          fSaveAllProperties: BOOL): HResult; stdcall;
    但是IPersistPropertyBag.Save 没运行到,而在VB里,当WORD保存的时候就会自动去运行UserControl_WriteProperties来保存属性
      

  9.   

    现在发现在VB和delphi里用这个OCX的时候可以正常保存属性,但就是在WORD里不行
      

  10.   

    看来大家都不怎么会,那有谁可以取到一个OCX的PropBag也可以啊,我在网上找了,只有对视频设备操作的一段代码,至于怎么取OCX的,就不知道了,要靠大家了,我把那段食视频设备的代码帖出来,希望大家帮忙
    利用BindToStorage,取PropBagprocedure TForm1.Button1Click(Sender: TObject);
    var
    SysDevEnum : ICreateDevEnum;
    EnumCat : IEnumMoniker;
    Moniker : IMoniker;
    Fetched : PLongint;
    PropBag : IPropertyBag;
    varName : OleVariant;begin
    Memo1.Clear;CoCreateInstance(CLSID_SystemDeviceEnum,
        nil, CLSCTX_INPROC, IID_ICreateDevEnum,SysDevEnum);SysDevEnum.CreateClassEnumerator(CLSID_VideoCompressorCategory,EnumCat,0);
                                    {CLSID_VideoInputDeviceCategory}if EnumCat<>nil then                                
    while (EnumCat.Next(1,Moniker,Fetched)=S_OK) do
      begin
      Moniker.BindToStorage(nil,nil,IPropertyBag,PropBag);  PropBag.Read('FriendlyName',varName,nil);  Memo1.Lines.Append(string(varName));
        PropBag:=nil;
        Moniker:=nil;
      end;EnumCat:=nil;
    SysDevEnum:=nil;
    end;end.