打造属于自己的sample framework(一)
2007-05-15 16:45
218 查看
将sample framework 做成用户控件
可能本文比较适合对 sample framework 有稍微了解的人。
前段时间研究了一下directx sdk里的sample framework。sample framework是一个非常强大的3d 引擎。这里有些心得体会想和大家一起分享,希望可以得到一些更强大和实际的应用。
今天我想写一下如何将sample framework做成控件。我里想的不仅仅是将 sample framework 做成用户控件, 而且可以实现动态的load dll.
首先创建一个类 IFrameWork:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class IFrameWork : UserControl, IDeviceCreation, IFrameworkCallback
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void OnFrameMove(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void OnFrameRender(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return true;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private Framework sampleFramework = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual Framework Framework
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
get
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return this.sampleFramework;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
set
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.sampleFramework = value;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
这里IFrameWork 继承自 UserControl, IDeviceCreation, IFrameworkCallback.
这里为什么要加一个sampleFramework 属性等下再解释.
对于把sample framework做成控件最关键的地方该在于 mainloop() 函数. 我看www.mdxinfo.com上看过一篇将原来的 main()的函数改成InitializeGraphics();
而且在方法的最后将 this.sampleFramework.MainLoop(); 删掉。
然后在主程序的main() 函数中添加
Form1 form = new Form1();
form.Show();
form.directXWindow.Framework.MainLoop();
来运行出控件模型。
其实这里有很多值得改进的地方。我们仔细分析一下MainLoop()方法。
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public void MainLoop()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
..
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//关键就是从这里开始
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
using (System.Windows.Forms.Control app = Window)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Hook the application's idle event
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Start the application
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (app is System.Windows.Forms.Form)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Show the window
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
app.Show();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
State.IsInsideMainloop = false;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
是在应用程序空闲的时候调用了绘图的方法。
而
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (app is System.Windows.Forms.Form)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Show the window
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
app.Show();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
是把函数的windows窗体的显示放在了这个方法里,而且占据了主线程。
所以出现上面才会采取将mainloop方法放在主窗体里。
这里面我们其实可以有更好的方法去实现:将上面的一段代码给删除掉。把主线程还给form的main() 函数。
我们添加一个方法:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public void RemoveIdleDelegate()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Idle -= new EventHandler(OnApplicationIdle);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
这个函数的用法在接下来的使用中就会明白。
到了这一步以后我们基本上可以实现把sample framework 做成一个用户控件了。
但是如何实现动态的load dll。
将以下代码:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class SampleControl : IFrameWork
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override void OnFrameMove(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridevoid OnFrameRender(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
..
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridebool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridevoid ModifyDeviceSettings(DeviceSettings settings, Caps caps)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private Framework sampleFramework = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override Framework Framework
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
get
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return this.sampleFramework;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
set
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.sampleFramework = value;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
编译成dll。
在主窗体里:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void openToolStripMenuItem1_Click(object sender, EventArgs e)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
OpenFileDialog dlg = new OpenFileDialog();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
dlg.Multiselect = true;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (DialogResult.OK == dlg.ShowDialog())
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
string sFileName = dlg.FileName;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Type[] types = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
try
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
types = Assembly.LoadFile(sFileName).GetTypes(); //动态加载dll
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (Type type in types)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (type.IsSubclassOf(typeof(IFrameWork)))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//D3dWindow是IFrameWork类型,就是我们的控件 。用于显示3d模型。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
D3DWindow.Framework.RemoveIdleDelegate(); // 释放掉 System.Windows.Forms.Application.Idle委托。在新的控件实例中才可以重新添加委托,绘制新的图形
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.splitContainer1.Panel1.Controls.Remove(D3DWindow); //删除掉原来的控件
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
D3DWindow = (IFrameWork)type.InvokeMember(null, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, null, null);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Dock = System.Windows.Forms.DockStyle.Fill;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Location = new System.Drawing.Point(0, 0);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Name = "D3DWindow";
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Size = new System.Drawing.Size(598, 506);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.TabIndex = 1;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.splitContainer1.Panel1.Controls.Add(D3DWindow); //加载新的控件。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
catch (Exception ex)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ex.ToString();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
到这里所有的工作就完成了。
可能本文比较适合对 sample framework 有稍微了解的人。
前段时间研究了一下directx sdk里的sample framework。sample framework是一个非常强大的3d 引擎。这里有些心得体会想和大家一起分享,希望可以得到一些更强大和实际的应用。
今天我想写一下如何将sample framework做成控件。我里想的不仅仅是将 sample framework 做成用户控件, 而且可以实现动态的load dll.
首先创建一个类 IFrameWork:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class IFrameWork : UserControl, IDeviceCreation, IFrameworkCallback
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void OnFrameMove(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void OnFrameRender(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual bool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return true;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual void ModifyDeviceSettings(DeviceSettings settings, Caps caps)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private Framework sampleFramework = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public virtual Framework Framework
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
get
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return this.sampleFramework;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
set
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.sampleFramework = value;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
这里IFrameWork 继承自 UserControl, IDeviceCreation, IFrameworkCallback.
这里为什么要加一个sampleFramework 属性等下再解释.
对于把sample framework做成控件最关键的地方该在于 mainloop() 函数. 我看www.mdxinfo.com上看过一篇将原来的 main()的函数改成InitializeGraphics();
而且在方法的最后将 this.sampleFramework.MainLoop(); 删掉。
然后在主程序的main() 函数中添加
Form1 form = new Form1();
form.Show();
form.directXWindow.Framework.MainLoop();
来运行出控件模型。
其实这里有很多值得改进的地方。我们仔细分析一下MainLoop()方法。
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public void MainLoop()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
..
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//关键就是从这里开始
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
using (System.Windows.Forms.Control app = Window)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Hook the application's idle event
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Start the application
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (app is System.Windows.Forms.Form)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Show the window
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
app.Show();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
State.IsInsideMainloop = false;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
是在应用程序空闲的时候调用了绘图的方法。
而
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (app is System.Windows.Forms.Form)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run(app as System.Windows.Forms.Form);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Show the window
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
app.Show();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Run();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
是把函数的windows窗体的显示放在了这个方法里,而且占据了主线程。
所以出现上面才会采取将mainloop方法放在主窗体里。
这里面我们其实可以有更好的方法去实现:将上面的一段代码给删除掉。把主线程还给form的main() 函数。
我们添加一个方法:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public void RemoveIdleDelegate()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
System.Windows.Forms.Application.Idle -= new EventHandler(OnApplicationIdle);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
这个函数的用法在接下来的使用中就会明白。
到了这一步以后我们基本上可以实现把sample framework 做成一个用户控件了。
但是如何实现动态的load dll。
将以下代码:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
public class SampleControl : IFrameWork
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override void OnFrameMove(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridevoid OnFrameRender(Device device, double totalTime, float elapsedTime)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
..
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridebool IsDeviceAcceptable(Caps caps, Format adapterFormat, Format backBufferFormat, bool isWindowed)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public overridevoid ModifyDeviceSettings(DeviceSettings settings, Caps caps)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private Framework sampleFramework = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public override Framework Framework
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
get
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return this.sampleFramework;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
set
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.sampleFramework = value;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
编译成dll。
在主窗体里:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void openToolStripMenuItem1_Click(object sender, EventArgs e)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
OpenFileDialog dlg = new OpenFileDialog();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
dlg.Multiselect = true;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (DialogResult.OK == dlg.ShowDialog())
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
string sFileName = dlg.FileName;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Type[] types = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
try
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
types = Assembly.LoadFile(sFileName).GetTypes(); //动态加载dll
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (Type type in types)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (type.IsSubclassOf(typeof(IFrameWork)))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//D3dWindow是IFrameWork类型,就是我们的控件 。用于显示3d模型。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
D3DWindow.Framework.RemoveIdleDelegate(); // 释放掉 System.Windows.Forms.Application.Idle委托。在新的控件实例中才可以重新添加委托,绘制新的图形
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.splitContainer1.Panel1.Controls.Remove(D3DWindow); //删除掉原来的控件
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
D3DWindow = (IFrameWork)type.InvokeMember(null, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, null, null);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Dock = System.Windows.Forms.DockStyle.Fill;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Location = new System.Drawing.Point(0, 0);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Name = "D3DWindow";
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.Size = new System.Drawing.Size(598, 506);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.D3DWindow.TabIndex = 1;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.splitContainer1.Panel1.Controls.Add(D3DWindow); //加载新的控件。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
catch (Exception ex)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ex.ToString();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
到这里所有的工作就完成了。
相关文章推荐
- 教你如何打造属于自己的QQ纯净版
- 打造属于自己的个性化GHOST XP系统安装盘
- 打造属于自己的博客app——基于react native和博客园接口
- 打造属于自己的进度条(笔记)
- 打造属于自己的FTP
- 手把手打造属于自己的Linux系统!
- 打造属于自己的 gVim !
- Vim+Ctags+TagList+WinManager+pydiction打造属于自己编译器(一)
- 如何动手打造属于自己的AlphaGo Zero?
- 打造属于自己的谷歌Maps版博客公告【演示+源码】
- 【系列索引】结合项目实例 回顾传统设计模式 打造属于自己的模式类系列
- 打造属于自己的设计模式
- 不用代码,10分钟打造属于自己的第一款小程序
- 用若琪的源代码打造属于自己的人工智能 | 开发日记精选
- 使用pysolr库操作solr(二 打造属于自己的搜索引擎)
- 打造属于自己的RxBus
- 如何打造属于自己的个人品牌
- 打造属于自己的支持版本迭代的Asp.Net Web Api Route
- 打造属于自己的图文符号库
- 怎样合法地打造一个属于自己的商业情报网络?