我正在尝试将属性添加到 AutoCAD 中的对象属性管理器 (OPM)。我正在关注这些文章第 1 部分 第 2 部分
我还从 Github 分叉了 this 项目,该项目遵循这些文章。
将所有设置设置为适用于 AutoCAD 2024 和 ObjectARX 2024 后,C++(我非常不熟悉)将进行编译和构建。
C# 部分也可以构建。但有些错误让人相信它不应该
[
Guid("F60AE3DA-0373-4d24-82D2-B2646517ABCB"),
ProgId("OPMNetSample.CustomProperty.1"),
// No class interface is generated for this class and
// no interface is marked as the default.
// Users are expected to expose functionality through
// interfaces that will be explicitly exposed by the object
// This means the object can only expose interfaces we define
ClassInterface(ClassInterfaceType.None),
// Set the default COM interface that will be used for
// Automation. Languages like: C#, C++ and VB allow to
//query for interface's we're interested in but Automation
// only aware languages like javascript do not allow to
// query interface(s) and create only the default one
ComDefaultInterface(typeof(IDynamicProperty2)),
ComVisible(true)
]
public class CustomProp : IDynamicProperty2 {
private IDynamicPropertyNotify2 m_pSink =null;
// Unique property ID
void IDynamicProperty2.GetGUID(out Guid propGUID)
{
propGUID = new Guid("F60AE3DA-0373-4d24-82D2-B2646517ABCB");
}
// Property display nameD
void IDynamicProperty2.GetDisplayName(out string szName)
{
szName = "My integer property";
}
// Show/Hide property in the OPM, for this object instance
void IDynamicProperty2.IsPropertyEnabled(object pUnk, out int bEnabled)
{
bEnabled = 1;
}
// Is property showing but disabled
void IDynamicProperty2.IsPropertyReadOnly(out int bReadonly)
{
bReadonly = 0;
}
// Get the property description string
void IDynamicProperty2.GetDescription(out string szName)
{
szName = "This property is an integer";
}
// OPM will typically display these in an edit field
// optional: meta data representing property type name,
// ex. ACAD_ANGLE
void IDynamicProperty2.GetCurrentValueName(out string szName)
{
throw new System.NotImplementedException();
}
// What is the property type, ex. VT_R8
void IDynamicProperty2.GetCurrentValueType(out ushort varType)
{
// The Property Inspector supports the following data
// types for dynamic properties:
// VT_I2, VT_I4, VT_R4, VT_R8,VT_BSTR, VT_BOOL
// and VT_USERDEFINED.
varType = 3; // VT_I4
}
// Get the property value, passes the specific object
// we need the property value for.
void IDynamicProperty2.GetCurrentValueData(object pUnk, ref object pVarData)
{
// TODO: Get the value and return it to AutoCAD
// Because we said the value type was a 32b int (VT_I4)
pVarData = (int)4;
}
// Set the property value, passes the specific object we
// want to set the property value for
void IDynamicProperty2.SetCurrentValueData(object pUnk, object varData)
{
// TODO: Save the value returned to you
// Because we said the value type was a 32b int (VT_I4)
int myVal = (int)varData;
}
// OPM passes its implementation of IDynamicPropertyNotify, you
// cache it and call it to inform OPM your property has changed
void IDynamicProperty2.Connect(object pSink)
{
m_pSink = (IDynamicPropertyNotify2)pSink;
}
void IDynamicProperty2.Disconnect()
{
m_pSink = null;
}
}
IDynamicProperty2
来自 C++ 项目,该项目负责将其提供给 .NET
//- IDynamicProperty2.h
#pragma once
using namespace System;
using namespace System::Runtime;
using namespace System::Runtime::InteropServices;
using namespace Autodesk::AutoCAD::Runtime;
using namespace Autodesk::AutoCAD::DatabaseServices;
#include "dynprops.h"
namespace Autodesk
{
namespace AutoCAD
{
namespace Windows
{
namespace OPM
{
[InteropServices::Guid("9CAF41C2-CA86-4ffb-B05A-AC43C424D076")]
[InteropServices::InterfaceTypeAttribute(InteropServices::ComInterfaceType::InterfaceIsIUnknown)]
[InteropServices::ComVisible(true)]
public interface class IDynamicProperty2
{
void GetGUID(
[InteropServices::Out] System::Guid% propGUID
);
void GetDisplayName(
[InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> name);
void IsPropertyEnabled(
[InteropServices::In,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::IUnknown
)
] Object^ pUnk,
[InteropServices::Out] System::Int32% bEnabled
);
void IsPropertyReadOnly(
[InteropServices::Out] System::Int32% bReadonly
);
void GetDescription(
[InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> description
);
void GetCurrentValueName(
[InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> name
);
void GetCurrentValueType(
[InteropServices::Out] ushort% pVarType
);
void GetCurrentValueData(
[InteropServices::In,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::IUnknown
)
] Object^ pUnk,
[InteropServices::In,
InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::Struct
)
] interior_ptr<Object^> varData
);
void SetCurrentValueData(
[InteropServices::In,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::IUnknown
)
] Object^ pUnk,
[InteropServices::In,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::Struct
)
] Object^ varData
);
void Connect(
[InteropServices::In,
InteropServices::MarshalAs(
/*IDynamicPropertyNotify2*/
InteropServices::UnmanagedType::IUnknown
)
] Object^ pSink
);
void Disconnect();
};
[InteropServices::Guid(
"975112B5-5403-4197-AFB8-90C6CA73B9E1"
)]
[InteropServices::InterfaceTypeAttribute(
InteropServices::ComInterfaceType::InterfaceIsIUnknown
)]
[InteropServices::ComVisible(true)]
public interface class IDynamicPropertyNotify2
{
void OnChanged(
[InteropServices::In,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::IUnknown
)
] Object^ pDynamicProperty
);
void GetCurrentSelectionSet(
[InteropServices::In,
InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::Struct
)
] interior_ptr<Object^> pSelection
);
};
}
}
}
}
这是
IDynamicProperty2
的声明,它是 ObjectARX API 的一部分,位于 dynprops.h
//--------------------------
// IDynamicProperty2 interface
// Implement this class to create dynamic properties for the PropertyPalette
// it defines the base set of property attributes as well as
// the name/type/data tuples.
//--------------------------
// {9CAF41C2-CA86-4ffb-B05A-AC43C424D076}
DEFINE_GUID(IID_IDynamicProperty2, 0x9caf41c2, 0xca86, 0x4ffb, 0xb0, 0x5a, 0xac, 0x43, 0xc4, 0x24, 0xd0, 0x76);
interface DECLSPEC_UUID("9CAF41C2-CA86-4ffb-B05A-AC43C424D076")
IDynamicProperty2 : public IUnknown
{
BEGIN_INTERFACE
// *** IUnknown methods ****
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID FAR* ppvObj) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
// *** IDynamicProperty2 methods ***
//Unique property ID
STDMETHOD(GetGUID)(THIS_ /*[out]*/GUID* propGUID) PURE;
// Property display name
STDMETHOD(GetDisplayName)(THIS_ /*[out]*/BSTR* bstrName) PURE;
// Show/Hide property in the OPM, for this object instance
STDMETHOD(IsPropertyEnabled)(THIS_ /*[in]*/IUnknown *pUnk,
/*[out]*/BOOL* pbEnabled) PURE;
// Is property showing but disabled
STDMETHOD(IsPropertyReadOnly)(THIS_ /*[out]*/BOOL* pbReadonly) PURE;
// Get the property description string
STDMETHOD(GetDescription)(THIS_ /*[out]*/BSTR* bstrName) PURE;
// *** Basic property value information ***
// OPM will typically display these in an edit field
// optional: meta data representing property type name, ex. ACAD_ANGLE
STDMETHOD(GetCurrentValueName)(THIS_ /*[out]*/BSTR* pbstrName) PURE;
// What is the property type, ex. VT_R8
STDMETHOD(GetCurrentValueType)(THIS_ /*[out]*/VARTYPE* pVarType) PURE;
// Get the property value, passes the specific object we need the property
// value for.
STDMETHOD(GetCurrentValueData)(THIS_ /*in*/IUnknown *pUnk,
/*[out]*/VARIANT* pvarData) PURE;
// Set the property value, passes the specific object we want to set the
// property value for
STDMETHOD(SetCurrentValueData)(THIS_ /*[in]*/IUnknown *pUnk,
/*[in]*/const VARIANT varData) PURE;
//*** Notifications ***
//OPM passes its implementation of IDynamicPropertyNotify, you
//cache it and call it to inform OPM your property has changed
STDMETHOD(Connect)(THIS_ /*[in]*/IDynamicPropertyNotify2* pSink) PURE;
STDMETHOD(Disconnect)(THIS_ ) PURE;
};
typedef IDynamicProperty2 FAR* LPDYNAMICPROPERTY2;
如果我尝试按照 Visual Studio 中的建议“修复”错误,那么当我去构建时会发生这种情况
这是更改后的代码
// Property display nameD
void IDynamicProperty2.GetDisplayName(ref string szName)
{
szName = "My integer property";
}
// Get the property description string
void IDynamicProperty2.GetDescription(ref string szName)
{
szName = "This property is an integer";
}
// OPM will typically display these in an edit field
// optional: meta data representing property type name,
// ex. ACAD_ANGLE
void IDynamicProperty2.GetCurrentValueName(ref string szName)
{
throw new System.NotImplementedException();
}
当我去构建时,我收到这些错误
我在c++项目的
IDynamicProperty2.h
文件中更改了这些声明
void GetDisplayName(
[InteropServices::In,//added
InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> name);
void GetDescription(
[InteropServices::In,//added
InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> description
);
void GetCurrentValueName(
[InteropServices::In,//added
InteropServices::Out,
InteropServices::MarshalAs(
InteropServices::UnmanagedType::BStr
)
] interior_ptr<System::String^> name
);
然后更改了 C# 代码以使用
ref
void IDynamicProperty2.GetDisplayName(ref string szName)
{
szName = "My integer property";
}
void IDynamicProperty2.GetDescription(ref string szName)
{
szName = "This property is an integer";
}
void IDynamicProperty2.GetCurrentValueName(ref string szName)
{
throw new System.NotImplementedException();
}
我在两个项目中都构建了这些更改,然后没有加载示例项目,效果很好!