My Blog! blog.gkong.com   

Tip of my blog

新年快乐!


阅读(1162) 评论(0)
标签(TAG):

LabWindows/CVI ActiveX Controller For Visual Basic 6.0 Users

9 评级 | 3.33 out of 5
The LabWindows/CVI ActiveX Controller Wizard generates C wrappers to call ActiveX servers. This document, which describes the wrappers generated by this tool, is intended for users who are more familiar using Microsoft Visual Basic 6.0 to control ActiveX servers or controls.

Introduction to LabWindows/CVI ActiveX Controller Wizard

Complete the following steps to generate wrappers with the ActiveX Controller Wizard:

  1. Select Tools»Create ActiveX Controller to open the ActiveX Controller Wizard and click Next in the Welcome panel.
  2. The LabWindows/CVI ActiveX Controller Wizard displays all the ActiveX servers and controls registered on your computer. You also can browse to and select an unregistered server or type library that is not listed. Select an ActiveX server and click Next.
  3. Enter a target file name and prefix. The wizard-generated code is in the form of a LabWindows/CVI instrument—this is similar to a C library with LabWindows/CVI function panel support. Based on the target file name, for example, MyClient.fp, LabWindows/CVI generates four files—MyClient.fp, MyClient.sub, MyClient.c, and MyClient.h.
  4. Click Compatibility Options to select one of the following options for wrapper functions to access properties:
    -- Per Property—If you select the per property option, the wizard will generate individual wrapper functions for each ActiveX property.
    -- Per Object—If you select the per object option, the wizard will generate a wrapper function for each ActiveX object to access all the properties of that object.
    -- Per Server—If you select the per server option, the wizard will generate a wrapper function to access all the properties of all the ActiveX objects in the server.
    Note that the per object and per server options are available only if the server exposes IDispatch based interfaces. National Instruments recommends that you use the default Per Property option because it supports both dispatch interfaces and custom interfaces.
    Click OK in the Compatibility Options dialog box and click Next.
  5. Click Advanced Options to open the ActiveX Controller Advanced Options dialog box. In this dialog box, the wizard displays the objects, methods, and properties of the ActiveX server and allows you to change the names used in generated wrapper functions and specify which methods and properties you want LabWindows/CVI to create wrapper functions for.
  6. Click OK to generate the LabWindows/CVI instrument.

Example Server

For example, consider that you have an ActiveX server named MyServer, with one object called MyObject exposing IMyInterface1 and IMyInterface2 interfaces. In this example, IMyInterface1 comprises the MyMethod1() method and the MyProperty1 "integer" property. IMyInterface2 comprises the MyMethod2() method and the MyProperty2 "integer" property. Figure 1 illustrates this object.


Figure 1: Example ActiveX Server Object


Wrapper Functions

Wrapper Naming Convention

The ActiveX Controller Wizard generates a function panel class for each interface implemented in the ActiveX server. In each of these function panel classes, the wizard generates New, Active, and Open functions if the interface is implemented by a creatable object. The names of the functions are generated according to the following rules:

<Prefix>_New<InterfaceName>
<Prefix>_Active<InterfaceName>
<Prefix>_Open<InterfaceName>

Note that if the same interface is implemented by another creatable object, for example, MyObject2, then the object names also are included in the wrapper function names according to the following rules:

<Prefix>_New<ObjectName><InterfaceName>
<Prefix>_Active<ObjectName><InterfaceName>
<Prefix>_Open<ObjectName><InterfaceName>

Using the preceding rules results in the following names:

MyServer_NewMyObjectIMyInterface1
MyServer_NewMyObject2IMyInterface1
.. .. ..

The LabWindows/CVI ActiveX Controller Wizard generates the following wrapper functions for the example server with the Property Access Functions option set to Per Property and MyServer as the instrument prefix.

Function Panel Class: IMyInterface1

HRESULT CVIFUNC MyServer_NewIMyInterface1 (

    const char *server,
    int supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_OpenIMyInterface1 (
    const char *fileName,
    const char *server,
    int supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_ActiveIMyInterface1 (
    const char *server,
    int supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_IMyInterface1MyMethod1 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo);

HRESULT CVIFUNC MyServer_IMyInterface1GetMyProperty1 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo,
    int *myProperty1);

HRESULT CVIFUNC MyServer_IMyInterface1SetMyProperty1 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo,
    int myProperty1);


Function Panel Class: IMyInterface2

HRESULT CVIFUNC MyServer_NewIMyInterface2 (
    const char *server,
    int  supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_OpenIMyInterface2 (
    const char *fileName,
    const char *server,
    int supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_ActiveIMyInterface2 (
    const char *server,
    int supportMultithreading,
    LCID locale,
    int reserved,
    CAObjHandle *objectHandle);

HRESULT CVIFUNC MyServer_IMyInterface2MyMethod2 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo);

HRESULT CVIFUNC MyServer_IMyInterface2GetMyProperty2 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo,
    int *myProperty2);

HRESULT CVIFUNC MyServer_IMyInterface2SetMyProperty2 (
    CAObjHandle objectHandle,
    ERRORINFO *errorInfo,
    int myProperty2);


The MyServer_NewIMyInterface1 and MyServer_NewIMyInterface2 wrapper functions create new instances of the object and are equivalent to the CreateObject function or New operator in Visual Basic. The MyServer_ActiveIMyInterface1 and MyServer_ActiveIMyInterface2 wrapper functions return the registered active object and are equivalent to calling the Visual Basic GetObject function with the path omitted. The MyServer_OpenIMyInterface2 and MyServer_OpenIMyInterface2 wrapper functions create the object from a file and are equivalent to calling the Visual Basic GetObject function with a valid path.

In the wrapper functions, ActiveX objects are represented by the LabWindows/CVI CAObjHandle type. This type is equivalent to the Visual Basic Object type. The generated "creation" functions have parameters to get the object from a remote server and get thread-safe or locale-specific object handles. Use the GetObjHandleFromActiveXCtrl function in the LabWindows/CVI User Interface Library to get the LabWindows/CVI ActiveX object handle of ActiveX controls loaded in LabWindows/CVI user interface panels.

Examples
  • Create a new object and get its IMyInterface1 interface:
    Visual Basic
    Dim obj As MyServer.MyObject
    Set obj = New MyServer.MyObject

    LabWindows/CVI
    CAObjHandle obj;
    MyServer_NewIMyInterface1(0, 1, LOCALE_NEUTRAL, 0, &obj);
  • Create a new MyObject and get its IMyInterface1 interface on a remote server:
    Visual Basic
    Dim obj As MyObject
    Set obj = CreateObject("MyServer.MyObject", "server_address")

    LabWindows/CVI
    CAObjHandle obj;
    MyServer_NewIMyInterface1("server_address", 1,
    LOCALE_NEUTRAL, 0, &obj);
  • Create the object from file and get its IMyInterface1 interface:
    Visual Basic
    Dim obj As MyObject
    Set obj = GetObject("file_path", "MyServer.MyObject")

    LabWindows/CVI
    CAObjHandle obj;
    MyServer_OpenIMyInterface1("file_path", 0, 1,
    LOCALE_NEUTRAL, 0, &obj);
  • Get the active object's IMyInterface1 interface:
    Visual Basic
    Dim obj As MyObject
    Set obj = GetObject(, "MyServer.MyObject")

    LabWindows/CVI
    CAObjHandle obj;
    MyServer_ActiveIMyInterface1(0, 1, LOCALE_NEUTRAL, 0, &obj);
  • Create a new MyObject and get its IMyInterface2 interface:
    Visual Basic
    Dim obj As IMyInterface2
    Set obj = CreateObject("MyServer.MyObject")

    LabWindows/CVI
    CAObjHandle obj;
    MyServer_NewIMyInterface2(0, 1, LOCALE_NEUTRAL, 0, &obj);
  • Get the ActiveX object handle for an ActiveX control loaded in a LabWindows/CVI panel:
    CAObjHandle obj;
    GetObjHandleFromActiveXCtrl(panelHandle, PANEL_CTRL, &obj);

Method and Property Wrappers

In the function panel classes corresponding to an ActiveX interface, the LabWindows/CVI ActiveX Controller Wizard generates wrapper functions for the methods and properties of that interface. The names of the functions are generated according to the following rules:

<Prefix>_<InterfaceName><MethodName>
<Prefix>_<InterfaceName>Get<PropertyName>
<Prefix>_<InterfaceName>Set<PropertyName>
<Prefix>_<InterfaceName>SetByRef<PropertyName>

For read-only properties, the Set and SetByRef wrappers are not generated. The SetByRef wrapper is generated if the server supports setting the property by reference. If a server exposes both Set and SetByRef accessors for a property, then you should refer to the server's documentation to decide between calling the Set or SetByRef wrappers. For write-only properties, the Get wrapper is not generated.

If you set the Property Access Functions option to Per Object, the wizard generates one group of get-set-setbyref property wrapper functions for all the properties in an interface. For these functions, you must pass the property ID and property type in addition to the object handle. These functions are named according to the following rules:

<Prefix>_Get<InterfaceName>Property
<Prefix>_Set<InterfaceName>Property
<Prefix>_Set<InterfaceName>PropertyByRef

If you set the Property Access Functions option to Per Server, the wizard generates one pair of get-set property wrapper functions for all the properties in the server. For these functions, you must pass the property ID and property type in addition to the object handle. These functions are named according to the following rules:

<Prefix>_GetProperty
<Prefix>_SetPropertyByRef

Note that the Per Object and Per Server options are available only if the server exposes IDispatch based interfaces. Also, the property wrapper functions generated for the Per Object and Per Server options require additional parameters to identify the property to get or set and its data type.

Examples

  • Call MyMethod1:
    Visual Basic
    Dim obj As MyObject
    Set obj = CreateObject( “MyServer.MyObject”)
    obj.MyMethod1
    LabWindows/CVI
    CAObjHandle obj;
    MyServer_NewIMyInterface1(0, 1, LOCALE_NEUTRAL, 0, &obj);
    MyServer_IMyInterface1MyMethod1(obj, 0);
  • Get, Set, and SetByRef MyProperty1:
    Visual Basic
    Dim obj As MyObject
    Dim myProp as Integer
    Set obj = CreateObject( “MyServer.MyObject”)
    myProp = obj.MyProperty1
    obj.MyProperty1 = 42
    Set obj.MyProperty1 = 42

    LabWindows/CVI
    CAObjHandle obj;
    int myProp;
    MyServer_NewIMyInterface1(0, 1, LOCALE_NEUTRAL, 0, &obj);
    MyServer_IMyInterface1GetMyProperty1(obj, 0, &myProp);
    MyServer_IMyInterface1SetMyProperty1(obj, 0, 42);
    MyServer_IMyInterface1SetByRefMyProperty1(obj, 0, 42);

Disposing Objects

In LabWindows/CVI, you must dispose the object handles by calling the CA_DiscardObjHandle function when you finish using the ActiveX object. This process is equivalent to setting the object to Nothing in Visual Basic. Disposing object handles is required to prevent memory leaks in your program. Note that for out-of-process ActiveX servers such as Microsoft Excel, Word, and so on, you also may have to call a Quit or Exit method on the top-level application object to ensure that the ActiveX server process exits.

    Visual Basic
    Dim obj As MyObject
    Set obj = CreateObject("MyServer.MyObject")
    Set obj = Nothing
    LabWindows/CVI
    CAObjHandle obj;
    MyServer_NewIMyInterface1(0, 1, LOCALE_NEUTRAL, 0, &obj);
    CA_DiscardObjHandle(obj);

ActiveX Threading Model

Before calling ActiveX components, the execution thread must initialize what is known as the ActiveX threading model. ActiveX threading is an advanced topic and beyond the scope of this document. In LabWindows/CVI, the default ActiveX threading model is the multithreaded model, which is set when you first call an ActiveX library function or wrapper function. In Visual Basic, the default threading model is the apartment-threaded model. While most ActiveX servers work in both threading models, some servers may work only in the apartment threaded model. For this reason, if you encounter a case where your Visual Basic code works, but the equivalent LabWindows/CVI code does not work, then you can try changing the LabWindows/CVI threading model to apartment threaded by calling the CA_InitActiveXThreadStyleForCurrentThread ActiveX Library function.

Note that you must call this function before calling any other ActiveX library functions or wrapper functions.

Optional Parameters

In Visual Basic you can omit passing values to optional parameters, which causes the server to use default values for such parameters. For non-variant optional parameters, LabWindows/CVI places the default value in the function panel control for that parameter. For optional parameters that are variants, LabWindows/CVI places a default value of CA_DEFAULT_VAL in the function panel. You can pass these values to get the same behavior as omitting optional parameters in Visual Basic.

Enumerating Collections

In Visual Basic you can iterate over collections using the For Each construct. ANSI C does not have a For Each construct, so you should iterate over the collection in for or while loops using the Item wrapper function to get an element of the collection. Most ActiveX collection interfaces expose an Item or similar method to index the collection.

The following example shows how to pass default values for optional parameters and enumerating collections. This example opens an Excel workbook and gets the names of all the worksheets in it.

Visual Basic
Dim app As Excel.Application
Dim s As Excel.Worksheet

Set app = CreateObject("Excel.Application")
app.Workbooks.Open ("c:\temp\book.xls")
For Each s In app.Sheets
    Text1.Text = Text1.Text & vbCrLf & s.Name
Next

LabWindows/CVI
int i, numSheets = 0;
CAObjHandle app = 0, books = 0, book = 0, sheets = 0;

Excel_NewApp(0, 1, LOCALE_NEUTRAL, 0, &app);

Excel_GetProperty(app, 0, Excel_AppWorkbooks,
CAVT_OBJHANDLE, &books);

Excel_WorkbooksOpen(books, 0, "c:\\temp\\book.xls",
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL, &book);

Excel_GetProperty(app, 0, Excel_AppSheets,
CAVT_OBJHANDLE, &sheets);

Excel_GetProperty(sheets, 0, Excel_SheetsCount,
CAVT_LONG, &numSheets);

for (i = 1; i <= numSheets; ++i)
{

    CAObjHandle sheet = 0;
    char * name = 0;
    // Get the sheet object at index i
    // CA_VariantLong is used to pass the index as a variant
    Excel_SheetsItem(sheets, 0, CA_VariantLong(i), &sheet);

    Excel_GetProperty(sheet, 0, Excel_WorksheetName,
    CAVT_CSTRING, &name);

    printf("Name of worksheet %d is %s\n", i, name);

    CA_FreeMemory(name);

    // Discard the temporary sheet object handle
    CA_DiscardObjHandle(sheet);
}

Duplicating Object References

In Visual Basic, you can use the Set statement to assign object references to properties. See the section Method and Property Wrappers for more information on the equivalent operation in LabWindows/CVI. You can also use duplicate object references using the Set command. In LabWindows/CVI, you can do the same using the CA_DuplicateObjHandle ActiveX Library function. This function is similar to the QueryInterface method of the COM IUnknown interface that is implemented by all ActiveX objects. Note that you can pass the GUID of the interface you want to the CA_DuplicateObjHandle function. You also can pass 0 if you want to get the same interface that is in the object handle being duplicated. You must discard the duplicated handle when you no longer need it.

Visual Basic
Dim obj as Object
Dim obj2 As MyServer.MyObject

'Create obj
.. ..
'Duplicate object reference
Set obj2 = obj
.. ..
Set obj2 = Nothing

LabWindows/CVI
CAObjHandle obj, obj2;

// Create obj
.. ..
CA_DuplicateObjHandle(obj, &IID_IMyInterface2, &obj2);
.. ..
CA_DiscardObjHandle(obj2);

Getting Interfaces from Objects

In most cases, you do not need to get the ActiveX interface pointers from the LabWindows/CVI object handles because all the wrapper functions use object handles to refer to the objects. However, sometimes you may have to call functions that take interface pointers as input or output parameters. You can use the LabWindows/CVI library functions to get interface pointers from object handles and object handles from interface pointers. The following code shows how to bind a Microsoft Grid ActiveX control to a Microsoft ADO Data Control ActiveX object.

Visual Basic
'Using the ADODC and Datagrid ActiveX controls
Adodc1.ConnectionString = DSNString
Adodc1.RecordSource = "SELECT * FROM  [Table1]"

'Assign the ADODC control as the data source
'to the DataGrid control.
Set DataGrid1.DataSource = Adodc1

LabWindows/CVI
// Get LabWindows/CVI ActiveX object handles for the ActiveX controls
GetObjHandleFromActiveXCtrl(panelHandle, PANEL_DATAGRID, &gridHandle);
GetObjHandleFromActiveXCtrl(panelHandle, PANEL_ADODC, &adoHandle);

// Set up ADO to use a database and have a query
MSAdodcLib_IAdodcSetConnectionString(adoHandle, NULL, DSNString);
MSAdodcLib_IAdodcSetRecordSource(adoHandle, NULL, "SELECT * FROM [Table1]");

// The Microsoft DataGrid expects a DataSource interface.
// This is automatically handled by Visual Basic.
CA_GetInterfaceFromObjHandle(adoHandle, &MSDATASRC_IID_DataSource, 1, &sourceIUnknown, NULL);
MSDataGridLib_IDataGridSetByRefDataSource(gridHandle, NULL,
sourceIUnknown);

Data Type Conversion

Like Visual Basic, LabWindows/CVI also converts ActiveX data types such as BSTR to native types like C string in the generated code. The generated code cannot automatically convert certain abstract ActiveX data types like SAFEARRAY and VARIANT. In this case, you can use the functions in the ActiveX Library to convert these data types to C types. Refer to the generated wrapper function help and the ActiveX Library help for more information about specific data type conversions.

Accessing Sub-Objects

In Visual Basic, you can access sub-objects nested at multiple levels such as the following:

app.Workbooks.Open("c:\temp\book.xls")

To execute this statement, Visual Basic creates a temporary Workbooks object and uses it to call the Open method. LabWindows/CVI does not support this syntax. You must access each sub-object one level at a time. That is, you must first get a handle to the Workbooks object and then use that handle to call the Open method as shown in the following example:

Visual Basic
Dim books as Workbooks
Dim book as Workbook

books = app.Workbooks
book = books.Open("c:\temp\book.xls")

LabWindows/CVI
ExcelObj_Workbooks books = 0;
ExcelObj_Workbook book = 0;

Excel_GetProperty(app, 0, Excel_AppWorkbooks, CAVT_OBJHANDLE, &books);

Excel_WorkbooksOpen(books, 0, "c:\\temp\\book.xls",
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL, &book);

CA_DiscardObjHandle(books);

Note that you must discard the Workbooks object when you no longer need it. Visual Basic automatically discards temporary objects.

ActiveX Events

To handle ActiveX events in Visual Basic, you use the WithEvents keyword in the Dim command used to define the ActiveX object. Visual Basic lists the events supported by the object in the drop-down menu and generates an event handler in your code when you select the event from the drop-down menu. LabWindows/CVI generates functions that you can use to register callback functions for the events you want to handle. All these event registration functions are generated in the Event Callback Registration Functions Class in the generated instrument. The prototypes of the callback functions are in the generated header file. The following example shows how to handle the WorkbookOpen event of the Excel application object.

Visual Basic
Dim WithEvents app As Excel.Application

Private Sub app_WorkbookOpen(ByVal Wb As Excel.Workbook)
MsgBox ("Workbook open event: " + Wb.Name)
End Sub

Private Sub Form_Load()
Set app = New Excel.Application
app.Workbooks.Open ("c:\temp\book.xls")
End Sub

'Other Code
.. .. ..


LabWindows/CVI
void main(void)
{

    ExcelObj_App app = 0;
    ExcelObj_Workbooks books = 0;
    ExcelObj_Workbook book = 0;

    Excel_NewApp(0, 1, LOCALE_NEUTRAL, 0, &app);
    Excel_AppEventsRegOnWorkbookOpen(app, WorkbookOpenCallback, 0, 1, 0);

    Excel_GetProperty(app, 0, Excel_AppWorkbooks, CAVT_OBJHANDLE, &books);

    Excel_WorkbooksOpen(books, 0, "c:\\temp\\book.xls",
    CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
    CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
    CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL,
    CA_DEFAULT_VAL, CA_DEFAULT_VAL, CA_DEFAULT_VAL, &book);

    .. .. ..
}

HRESULT CVICALLBACK WorkbookOpenCallback(CAObjHandle caServerObjHandle, void *caCallbackData, ExcelObj_Workbook wb)
{
    char * name;

    Excel_GetProperty (wb, 0, Excel_WorkbookName,
    CAVT_CSTRING, &name);
    MessagePopup("WorkbookOpen", name);
    CA_FreeMemory(name);
    return S_OK;
}

Getting Error Information

In Visual Basic, you handle ActiveX errors using the On Error statement. In LabWindows/CVI, the generated wrapper functions return error codes. Negative return values indicates an error condition, and you can get more information using the Error Processing functions in the ActiveX Library. Most of the time, this information is insufficient because the error code is a library error code or system error code and does not contain information from the server. The LabWindows/CVI generated wrapper function also contains an ERRORINFO output parameter that you can use to get additional error information from the server as shown in the following example:

void main(void)
{

    CAObjHandle app = 0, books = 0;
    HRESULT error;
    ERRORINFO errorInfo;

    error = Excel_NewApp(0, 1, LOCALE_NEUTRAL, 0, &app);
    if (error < 0)
    goto Error;
    error = Excel_GetProperty(app, &errorInfo, Excel_AppWorkbooks, CAVT_OBJHANDLE, &books);
    if (error < 0)
    {
      CA_DisplayErrorInfo(app, "Error", error, &errorInfo);
      goto Error;
    }
    // Other code
    .. .. ..
Error:
    // Handle error
    .. .. ..
}

Getting Help Information

When LabWindows/CVI generates wrapper functions, it extracts the ActiveX help information from the server's type library and provides the help information in the generated function panel. If the server's type library indicates that more help is available in an external help file, then LabWindows/CVI inserts appropriate links in the generated function panel and displays the help topic from the function panel. In order for the links to work in LabWindows/CVI and Visual Basic, the help file should be installed on the system – many Microsoft Office servers such as Excel, Word, and Outlook have external help files that are not installed by default. Make sure you install these files to get detailed help. Sometimes the servers are documented online, for example, on the Microsoft Developer Network (MSDN) for many Microsoft ActiveX servers and controls.

Conclusion

This document described some common issues that Visual Basic users encounter when writing programs in LabWindows/CVI to call ActiveX servers. Many of these issues also apply to users who program in other languages like C++, Java, C#, and so on. For more comprehensive information about ActiveX programming in LabWindows/CVI, refer to the ActiveX Library reference in the LabWindows/CVI Help and the shipping ActiveX example programs. You also can find useful information on the following sites:
http://forums.ni.com
http://www.ni.com/support/

Related Links:
NI Discussion Forums
NI Technical Support
Microsoft Developers Network
Building ActiveX Servers in LabWindows/CVI

by 进化中的兔子 发表于:2010/9/20 11:37:07
My subject | 我的主题

New entries | 新发表

Messages Board | 留言板


Guest Comments | 新评注


Blogger Login | 登陆栏
Blog Infomation | 信息栏
博客名称:嵌入式系统&虚拟仪器 日志总数:450 评论数量:277 访问次数:1781236 建立时间::2005年10月25日
Blog Infomation | 搜索栏
Blog Infomation | 收藏栏

XML RSS 2.0

嵌入式系统&虚拟仪器
© COPYRIGHT 2004 ALL RIGHTS RESERVED http://www.gkong.com

中华工控网 | 联系我们 | 工控论坛首页 | 工控博客首页 | 博客注册 | 博客登陆

工控博客管理联系邮箱:工控博客服务邮箱

中华工控网 © Copyright 2013. All rights reserved.