IT people's Paradise

  DonewsBlog  |  Donews首页  |  Donews社区  |  Donews邮箱  |  我的首页  |  联系作者  |  聚合   |  登录
  20篇文章 :: 0篇收藏:: 12篇评论:: 0个Trackbacks

公告

Site Counter

文章

收藏

相册

Blog Links

Site Links

存档


正在读取评论……


2007年07月


        格式优美的代码不但让人赏心悦目,而且可以方便阅读。开发团队之间更需要一个统一的代码风格。可是,写perl程序的人大都是懒惰之人,在写代码的同时还顾及风格,实在是累人的事情,不符合“lazy”的传统。

  以前我在用vim写perl小程序的时候,格式常常是率性而为,即使有vim帮忙负责缩进,最后的格式也是不尽人意。我是个有点追求完美的人,我就想 着如果在我写完乱七八糟的代码后,有个程序能像变魔术一样把代码整理得漂漂亮亮的,那就再好不过了。庆幸的是,我很快找到了它————那就是 perltidy。

  perltidy的是sourceforge的一个小项目,你可以在这里找到它:http://perltidy.sourceforge.net/ 。安装比较简单,看着README就可以搞定了。如果你懒得看英文,也可以看看fayland写的安装步骤:http://www.fayland.org/journal/PerlTidy.html

  我是在windows下安装的,之前已经安装了activeperl等。安装perltidy后,它会在perl的目录bin下产生两个文件 perltidy 和 perltidy.bat。由于perl的bin目录已经在我们的path里面,所以在命令行界面可以直接运行perltidy了。具体的可以看其帮助文 件。

  当然,如果写一段就需要在命令行运行perltidy,那也不够符合lazy的要求。下面我们配置一下vim,使得我们在写代码的时候,不离开vim就可以美化我们代码。

  在 _vimrc 中(linux下是.vimrc)中加入如下配置:

"Perl代码格式化工具,前提是安装了perltidy;
map ,pt  <Esc>:%! perltidy<CR>

  写完perl代码后,在vim命令模式下,输入命令“,pt”就可以直接整理代码格式了。

  如果你的perl代码有语法错误,perltidy也会识别并生成一个错误文件,其中包含了语法错误所在的位置。

  还在等什么,赶紧试试吧。




Part One, The Win32 DLL Object

First, we are going to make the Win32 DLL core files for the project, W32DLL.xxx.

  1. Start Visual C++ Studio.
  2. Close any open workspace and all files.
  3. Select New from the file menu.
  4. Select Project: Win32 Dynamic-Link Library.
  5. Give the the project a fitting name, say, W32DLL, make sure the location is acceptable and click OK.
  6. Select the "A simple DLL project" radio button.
  7. Click Finish and OK.

Next, we are going to make the DLL declaration/header file: DLLCode.h. Select New from the file menu, then select "C/C++ Header File" and name the file DLLCode. Click OK.

Copy and paste the following code excerpt:

Collapse
/*******************************************************
File name: DLLCode.h

This file contains all the DLL interfacing object
declarations, in this example:
a class object, two global function object, and
a global integer variable.
Notice: we use the same header file for compiling the
.DLL and the .exe (application).
This header file defines a macro which export the target
DLL objects if we are building
a DLL, otherwise it import the DLL objects into an
application which uses the DLL. If
we define DLLDIR_EX (a preprocessor identifier),
then the preprocessor define macro
DLLDIR (a mnemonic for DLL import/export Direction)
becomes an export instruction,
otherwise its an import instruction by default.
************************************************************/

#ifdef DLLDIR_EX
#define DLLDIR __declspec(dllexport) // export DLL information
#else
#define DLLDIR __declspec(dllimport) // import DLL information
#endif

// The extern "C" declaration allows mixed languages compactability,
// it prevents the C++ compiler from using decorated (modified)
// names for the functions
extern "C" {
void DLLDIR DLLfun1(char*);
int DLLDIR DLLfun2(int);
};
extern int DLLDIR DLLArg;

class DLLDIR DLLclass
{
public:
DLLclass(); // Class Constructor
~DLLclass(); // Class destructor
int Add(int, int); // Class function Add
int Sub(int, int); // Class function Subtract
int Arg; // Warning: you should not
// import class variables
// since the DLL object can be dynamically unloaded.
};

Save and close this header file. Now we are going to create the DLL implementation file, DLLCode.cpp.

Select New from the file menu, then select "C++ Source File" and name the file DLLCode. Then click OK.

Copy and paste the following code excerpt:

Collapse
/*********************************************************
File name: DLLCode.cpp

The header file, DLLCode.h, prototypes
all of the DLL interface objects
**********************************************************/

#include "Stdafx.h"
#include "DLLCode.h"
#include <iostream>

using namespace std;

void DLLfun1(char* a)
{
cout << a << endl;
};

int DLLfun2(int a) { return a<<1; };

int DLLArg = 100;

DLLclass::DLLclass() {};
DLLclass::~DLLclass() {};

int DLLclass::Add(int a, int b)
{
return a + b;
};

int DLLclass::Sub(int a, int b)
{
return a - b;
};

We want to access the DLL, so we need to export it. When the DLL is built, it also builds something called an export library. The export library is similar to a regular library. It contains all of the information necessary to dynamically link to the DLL at runtime. When we export a function or a class, the function name and location is stored in the export library. The application uses the DLL links in the export library to access the DLL.

To create the DLL export library, select "setting..." from the Project menu. Select the C/C++ tab. Append, or insert, ",DLLDIR_EX" (without the quotation marks) to the Preprocessor Definition text box. Then click OK. This will prevent compiler assumptions and warnings.

Note, Visual C++ defines an export macro <projectname>_EXPORTS, in our case, W32DLL_EXPORTS. But we used DLLDIR_EX, a generic macro name.

Click the "!" button to compile, build, and run the W32DLL project.

Close the "Executable For Debug Session" dialog box, we ran the DLL prematurely.

Congratulation, you finished building the Win32 DLL and its export Library.

Part Two, DLL Client Application One

This is the simplest and most versatile DLL Client, without MFC. This flexibility is due to the DLL export library information.

Now, we are going to make a Win32 console application, project DLLClient1. In this application, the DLL is loaded at application startup, "Load Time" linkage.

  1. Close any open workspace and files, then select New from the File menu.
  2. Select Win32 Console Application.
  3. In the Project name box, give the project a fitting name, say, DLLClient1, then click Next.
  4. Select "An empty project", then click Finish and OK.

Next, we are going to make the C/C++ source file: DLLClient1. Select New from the File menu, then select "C/C++ Source File". In the File Name box, give it a fitting name, say, DLLClient1, then press the Enter key.

Copy and paste the following code excerpt:

Collapse
/***********************************************************
File name: DLLClient1.cpp
***********************************************************/

#include <iostream>
#include <conio.h>
#include <windows.h>
#include "DLLCode.h"
#pragma comment(lib,"W32DLL.lib")

using namespace std;

int main()
{
int a, b, c;
DLLclass classFromDLL;
classFromDLL.Arg = 6;
a = classFromDLL.Add(3, 2);
b = classFromDLL.Sub(3, 2);
c = classFromDLL.Arg;

cout << "DLL class Add function return: " << a << endl;
cout << "DLL class Sub function return: " << b << endl;
cout << "DLL class Arg Variable return: " << c << endl;
getch();

a = DLLArg;
b = DLLfun2(30);

DLLfun1("this is the string pass to function DLLfun1");

cout << "\n\nDLL Variable DLLArg return: " << a << endl;
cout << "DLL function DLLfun2 return: " << b << endl;
getch();

return 0;
}

Save and close this C++ source file, then minimize the VC++ Studio window. We must get some common files from the W32DLL project. So, Copy, don't move, the following files to the DLLClient1 project directory:

  • W32DLL\Debug\W32DLL.DLL
  • W32DLL\Debug\W32DLL.lib
  • W32DLL\DLLCode.h

If you don't see the .DLL file in the Debug or Release folders, then select the View, or Tool (depending on the operating system) menu option, then select Folder Options. Next click on the View tab. Select option: Show all files. Then re-examine the Debug or Release folder.

Now maximize the VC++ Studio window, then click the "!" button to compile, build, and run the application.

If you have a DLL you use in many projects, then you can take advantage of the VC++ file architecture. Copy the DLL file into the system directory and the LIB file into the Visual C++ Lib directory. See Options on the Tools menu, and select the Directories tab, there are search directories for EXEs, SOURCE CODEs, and LIBs.

In this part, the DLL is loaded at application startup time. The Operating System searches the DLL in the following locations:

  • The Windows System directory
  • The Windows directory
  • The Application local path
  • The directories listed in the environment path variable

For simplicity, we just copy the common files to the target directory, DLLClient1.

Part Three, DLL Client Application Two

This DLL Client is for DLLs which do not have an export library, hints, we can't import the DLL header file. Note, we are restricted to function calls.

Now, we are going to make a Win32 console application, project DLLClient2.

In this application, the DLL is loaded during execution of the application, "Run Time" DLL linkage.

  1. Close any open workspace and files, then select New from the File menu.
  2. Select Win32 Console Application.
  3. In the Project Name box, give the project a fitting name, say, DLLClient2, then click Next.
  4. Select "An empty project", then click Finish and OK.

Next, we are going to make the C/C++ source file DLLClient2.

Select New from the File menu, then select "C/C++ Source File". In the File Name box, give it a fitting name, say, DLLClient2, then press the Enter key.

Copy and paste the following code excerpt:

Collapse
/************************************************************
File name: DLLClient2.cpp
************************************************************/

#include <conio.h> // Header file containing getch() prototype
#include <iostream>
#include <windows.h>

using namespace std;

typedef void (*MYFUN1)(char*); // pointer to: void function(char*)
typedef int (*MYFUN2)(int); // pointer to: int function(int)
int main()
{

MYFUN1 pfun1;
MYFUN2 pfun2;
HMODULE hMod; // handle to loaded library module
BOOL bRes; // BOOL to check if DLL was successfully unloaded

// returns a handle to the DLL, otherwise NULL
hMod = LoadLibrary("W32DLL.DLL");

// returns the address of the DLL functions, otherwise NULL
pfun1 = (MYFUN1) GetProcAddress(hMod, "DLLfun1");
pfun2 = (MYFUN2) GetProcAddress(hMod, "DLLfun2");

// (DLL function address) (function parameters)
(pfun1)("this is the string pass to function DLLfun1");

// (DLL function address) (function parameters)
int a = (pfun2) (30);

cout << "DLL function DLLfun2 return: " << a << endl;
cout << "Press a key to exit" << endl;
getch();

///////////////////////////////////////////////////////
// This code will run if you compile the W32DLL project
// with the W32DLL.def file to explicitly export DLLArg.
int *i;
i = (int*) GetProcAddress(hMod, "DLLArg");

if (i)
{
cout << "Variable DLLArg is: " << *i << endl;
};

cout << "Press a key to exit" << endl;
getch();

// returns nonzero if sucussful
bRes = FreeLibrary(hMod);
return 0;
}
// =========== Code snippet 4 ====================

Save and close this C++ source file, then minimize the VC++ studio window. Copy, don't move, the following file to the DLLClient2 project directory:

W32DLL\Debug\W32DLL.DLL

Now maximize the VC++ Studio window, then click the "!" button to compile, build, and run the application.

In this part, the DLL is loaded at application run time. The LoadLibrary function is used to load a DLL at run time. Being that we dynamically loaded the library, we should free this resource when we are finished with it.

Addendum

This subsection was added as a result to user Hing's comment.

The code in "Code snippet 4" was modified to add code for accessing the global variable DLLArg. Note, in the application you just ran, DLLCient2, function call GetProcAddress(hMod, "DLLArg") returned a NULL pointer. To add the global variable name to the DLL object, you must add a new text file to the W32DLL project. Go to New on the File menu. Select "Text File" on the File tag. Name the file: "W32DLL.def", the "def" file extension is important. Click OK.

Add the following text:

;File: W32DLL.def (explicitly export the global object names.)
LIBRARY W32DLL.dll
EXPORTS
DLLfun1
DLLfun2
DLLArg

Save and recompile the W32DLL project. Copy the new W32DLL.DLL file to the project DLLClient2 directory. Run the DLLClient2 application.

Function GetProcAddress should find variable "DLLArg".

Note: You CANNOT export a class object to the DLL. The library object contains that information, along with the header file.

Part Four, MFC DLL Object

This time, we are going to make the MFC DLL core files for the project, RMFCDLL.xxx.

  1. Start Visual C++ Studio.
  2. Close any open workspace and all files.
  3. Select New from the File menu.
  4. Select Project: MFC AppWizard(DLL).
  5. Give the the project a fitting name, say, RDLLMFC, make sure the location is acceptable and click OK.
  6. Select the "Regular DLL using shared MFC DLL" radio button.
  7. Click Finish and OK.

Next, we are going to make the DLL declaration header file: DLLCode.h. Select New from the File menu, then select "C/C++ Header File" and name the file DLLCode. Click OK.

Copy and paste the following code excerpt:

Collapse
/******************************************************
File name: DLLCode.h

This file contains MFC objects, hints,
you should use a MFC Client.
Notice: we use the same header file for compiling
the .DLL and the .exe (application).
This header file defines a macro which export the
target DLL objects if we are building
a DLL, otherwise it import the DLL objects into an
application which uses the DLL. If
we define DLLDIR_EX (a preprocessor identifier),
then the preprocessor define macro
DLLDIR (a mnemonic for: DLL import/export Direction)
becomes an export instruction,
otherwise its an import instruction by default.
******************************************************/

#ifdef DLLDIR_EX
#define DLLDIR __declspec(dllexport)
#else
#define DLLDIR __declspec(dllimport)
#endif

extern "C" {
// We delete the function DLLfun1 (as defined
// in the W32DLL DLL) it writes to
// a console, not a window, it isn't appropriate to
// call it from a MFC Client.
int DLLDIR DLLfun2(int);
void DLLDIR DrawEllipse ( CRect, CDC* ); // a MFC function call
};

extern int DLLDIR DLLArg;

class DLLDIR DLLclass
{
public:
DLLclass(); // Class Constructor
~DLLclass(); // Class destructor
int Add(int, int); // Class function Add
int Sub(int, int); // Class function Subtract
int Arg;
};

Save and close this header file. Now we are going to create the DLLCode.cpp file. Select New from the File menu, then select "C++ Source File". Name the file: DLLCode. Click OK. Copy and paste the following code excerpt:

Collapse
/************************************************************
File name: DLLCode.cpp

The header file, DLLCode.h, prototypes all
of the DLL interface objects
*************************************************************/

#include "StdAfx.h"
#include "DLLCode.h"

int DLLfun2(int a) { return a<<1; };

int DLLArg = 100;

DLLclass::DLLclass() {};
DLLclass::~DLLclass() {};

int DLLclass::Add(int a, int b)
{
return a + b;
};

int DLLclass::Sub(int a, int b)
{
return a - b;
};

void DrawEllipse ( CRect rect, CDC *pDC )
{
CBrush brush;
brush.CreateSolidBrush(RGB(0,0,255));
pDC->SelectObject(&brush);
pDC->Ellipse(&rect);
};

Now, select "setting..." from the Project menu. Select the C/C++ tab. Append, or insert, ",DLLDIR_EX" (without the quotation marks) to the Preprocessor Definition text box. Then click OK.

Click the "!" button to compile, build, and run the RDLLMFC project. Close the "Executable For Debug Session" dialog box, we ran the DLL prematurely. Congratulations, you finished building the Win32 DLL and its export Library.

Part Five, DLL MFC Client Application

This client application is a MFC application. It provides the framework, a window, for the MFC CBrush object used in the DLL function DrawEllipse.

Now, we are going to make the MFC application project MFCAp.

  1. Close any open workspace and files, then select New from the File menu.
  2. Select Project: MFC AppWizard(exe).
  3. In the Project name box, give the project a fitting name, say, MFCAp, then click OK.
  4. Select the "Single document" radio button, then click Finish and OK.

Select "ClassWizard..." from the View menu. The Message Maps tab should be active. In the "Class name:" dropdown box, select "CMFCApView". In the "Message functions:" list box, double click the "OnDraw" function label.

You should see the View class OnDraw function code. Replace that stub code with the following code excerpt, use copy and paste:

Collapse
///////////////////////////////////////////////
// CMFCApView drawing

void CMFCApView::OnDraw(CDC* pDC)
{
// DLL MFC Library function call
CRect rect;
rect.top=10;
rect.left=10;
rect.right=200;
rect.bottom=200;
DrawEllipse(rect,pDC);

// DLL class object call
int a, b, c;
CString str;
DLLclass classFromDLL;
classFromDLL.Arg = 6;
a = classFromDLL.Add(3, 2);
b = classFromDLL.Sub(3, 2);
c = classFromDLL.Arg;

// Display data in window
int y = 250, dy;
TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);
dy = tm.tmHeight + tm.tmExternalLeading;
str.Format("DLL class Add function return: %d", a);
pDC->TextOut(20, y, str);
y += dy;
str.Format("DLL class Sub function return: %d", b);
pDC->TextOut(20, y, str);
y += dy;
str.Format("DLL class Arg Variable return: %d", c);
pDC->TextOut(20, y, str);
y += dy;
a = DLLArg;
b = DLLfun2(30);
str.Format("DLL class Arg Variable return: %d", a);
pDC->TextOut(20, y, str);
y += dy;
str.Format("DLL function \"DLLfun2\" return: %d", b);
pDC->TextOut(20, y, str);
}

At the top of the file MCFApView.cpp, and somewhere after the line containing: #include "stdafx.h", insert the following line:

#include "DLLCode.h"

Save and close the MFCApView.cpp file. Select "Setting..." from the Project menu. Select the "Link" tab. In the "Object/Library modules:" text box, enter: "RDLLMFC.lib", without the quotation marks. Then click OK.

Now, minimize the VC++ Studio window. Copy the following files to the MFCAp project directory:

  • RDLLMFC\Debug\RDLLMFC.DLL
  • RDLLMFC\Debug\RDLLMFC.lib
  • RDLLMFC\DLLCode.h

Now maximize the VC++ Studio window, then click the "!" button.

A note in closing, you shouldn't change the DLL interface, especially class objects which are exported therein, because the v-table and class size are fitted at compile time. If you change the DLL and other programs are using it, you should rename the new version; or alternatively, you should re-compile all programs based on that DLL with the new interface.




Introduction

     In today's enterprises, different types of data are sitting in various data stores. Relational data is most likely to be in a SQL Server database or Oracle database. Many enterprise applications have their own database with its own data and data model. User and account information reside in a directory like Active Directory or Active Directory Application Mode. For more information about the directory services, please refer to the following article. Smaller, more fluent and mobile data sits in Excel spreadsheets or Microsoft Access databases. Each enterprise has large amounts of files like Word documents, Excel Spreadsheets, HTML documents, etc. which are sitting on a file system. It's a common practice to use Microsoft Indexing Server to index all the files sitting on the file system or a web server. Microsoft Indexing Server creates an indexing catalog and also provides a SQL query interface which enables you to simply search the index. For more information about Microsoft Indexing Server please refer to the following article.

The challenge enterprises are facing now is how to provide a complete and easy view into all this data sitting in various stores. More over how can you search all this data in various data sources without having to create many different interfaces or create complex search mechanisms? The good news is that most of these data stores provide a SQL query language. The SQL language varies slightly from one data source to another. For example directories like Active Directory provide a query capability but do not allow you to update, insert or delete data through SQL language. The same holds true for the SQL language of Microsoft Indexing Server. But most of the data sources provide the basic SQL query capability. Moreover Microsoft SQL Server allows you to link to other data stores which provide a SQL query language. This allows you to create a single SQL query spawning multiple data sources. This article explains how you can achieve this.

Linking other data stores to Microsoft SQL Server

Microsoft SQL Server provides the capability to link to other data sources which provide SQL query language. The Enterprise Manager of SQL Server shows in the left side navigation pane the "SQL Server groups" and under each all the database servers. It shows by default the local database server as "(local)". You can link other data stores to individual database servers. Expand a database server with the plus sign and you will find an entry called "Security". Expand the "Security" entry with the plus sign and you will see an entry called "Linked Servers". Expand the "Linked Servers" entry to see all the data stores which have been linked to this database server.

To link a new data store, right click on the entry "Linked Servers" and select "New Linked Server" from the popup menu. In the "Linked Server Properties" dialog you can enter a name for this linked server and then select whether you want to link another SQL Server database or any other data source. If you choose "SQL Server" then the linked server name must be the name of the SQL Server database you want to link to. For example if you have another SQL Server database running on the machine Enterprise-Minds then you would enter "Enterprise-Minds" as the linked server name. If you choose "Other data source" then you need to select from a list of existing data source providers, for example "Microsoft Jet 4.0 OLE Provider". Based on which provider you choose you need to enter the product name, data source, provider string, location and catalog. When you are done, click OK to create a link to this new data store. This new data source will now show up under "Linked Servers" with whatever name you had entered.

Link Microsoft SQL Server to a directory

You can link SQL Server to a directory like Active Directory or Active Directory Application Mode. Create a linked server in the Enterprise Manager and give it a descriptive name like "Active Directory Link". Choose the option "Other data source" and select the data provider "OLE DB Provider for Microsoft Directory Services". As product name enter "Active Directory Services" and as data source enter "adsdatasource". When you expand the new linked server you will find two available items - Tables and Views. So SQL Server allows you to view any tables or views in this data source. But the data provider "OLE DB Provider for Microsoft Directory Services" does not provide either the tables or views. Therefore you will get the error "Error 7301: Could not obtain a required interface from OLEDB provider ADsDSOObject". You can safely ignore the error message. You will be able to query the data store through the SQL query language.

It is important that you run the services "MSSQLSERVER" under an account which has access to the directory. If you run the services under the local system account you will get the following error when you try to query the data store:

Server: Msg 7321, Level 16, State 2, Line 1
An error occurred while preparing a query for
execution against OLE DB provider 'ADsDSOObject'.
OLE DB error trace [OLE/DB Provider 'ADsDSOObject'
CommandPrepare::Prepare returned 0x80040e14].

So if the directory runs on your local machine and the local user "DirectoryUser" has access to it then you need to run the "MSSQLSERVER" service under this account. If the directory is running somewhere in your domain and the domain user "DomainUser" has access to it then you need to run the "MSSQLSERVER" service under this domain account.

Link Microsoft SQL Server to a Microsoft Indexing Server catalog

You can also link SQL Server to an Indexing Server catalog. Create a new linked server and give it a descriptive name, for example WEBCATALOG if you are linking to the Web Indexing Server catalog. Next select "Other data source" and choose as data provider "Microsoft OLE DB Provider for Indexing Service". Enter as product name "Index Server" and as data source the name of the Indexing Server catalog, for example Web. When you expand the new linked server you will find two available items - Tables and Views. So SQL Server allows you to view any tables or views in this data source. But the data provider "Microsoft OLE DB Provider for Indexing Service" neither provides the tables nor views. Therefore you will get an error "Error 7301: Could not obtain a required interface from OLEDB provider MSIDXS". You can safely ignore the error message. You will be able to query the data store through the SQL query language.

Link Microsoft SQL Server to a Microsoft Access database

SQL Server can also be linked to a Microsoft Access database. Create a new linked server and give it a descriptive name, for example "Booklist". Next select "Other data source" and choose as data provider "Microsoft Jet 4.0 OLE DB Provider". Enter as product name "Access" and as data source the path to Microsoft Access file, for example "c:\My files\Books.mdb". This data provider is able to show the list of tables and views. So when you expand the Table's or View's item under this linked server you will see the list of tables or views in the Microsoft Access database.

Link Microsoft SQL Server to a Microsoft Excel spreadsheet

SQL Server can also be linked to a Microsoft Excel spreadsheet. Create a new linked server and give it a descriptive name, for example "Booklist". Next select "Other data source" and choose as data provider "Microsoft Jet 4.0 OLE DB Provider". Enter as product name "Jet 4.0", as data source the path to the Microsoft Excel spreadsheet - for example "c:\My files\Books.xls" - and finally as provider string enter "Excel 5.0". This data provider shows under Tables the list of excel worksheets. It does not show any Views.

There are many other providers available, which allow you to link up SQL Server with a variety of different data sources. The following link lists some of the available data providers which can be used by SQL Server.

How to query linked servers?

Now we have learnt how to link SQL Server with a variety of different data stores. To query data from a linked server you can use the command OPENQUERY in your FROM clause, which means you can query data from a linked server instead of a standard SQL Server table or view. The command OPENQUERY requires two parameters. First is the name of the linked server followed by the query you want to execute against this linked server. The following example assumes that you have a linked server with the name Books which has a table called Books:

SELECT * FROM OPENQUERY(Books, 'SELECT * FROM Books') AS Books

The query you pass along in the OPENQUERY command needs to be supported by the linked data provider. So depending on the data provider it might vary slightly. You can join the data from any linked data source or SQL Server table together. The next example assumes that you query a linked data source and join it together with a SQL Server table called BookValue.

SELECT * FROM OPENQUERY(Books, 'SELECT * FROM Books') AS Books INNER JOIN 
BookValue ON Books.ID = BookValue.ID

How to query a directory?

The "OLE DB Provider for Microsoft Directory Services" accepts two different syntaxes. One is called the LDAP dialect and the other the SQL dialect . As its name suggests the SQL dialect follows the SQL language syntax. You specify for the SELECT keyword the directory attributes you want to query for. For the ORDER BY and WHERE keywords you specify the attributes to sort on and to filter by. And for the FROM keyword you specify which directory and directory container to query for. The following example queries the container "OU=Enterprise-Minds,CN=Vancouver" in the Enterprise-Minds directory. It returns the common name and returns only the directory objects of the type group.

SELECT * FROM OPENQUERY(ADAM,
'SELECT cn FROM ''LDAP://Enterprise-Minds/OU=Enterprise-Minds,
CN=Vancouver'' WHERE objectClass=''group'' ')

Please note that the FROM clause needs to be put under two single quotes (escape sequencing of single quotes within a string which is already under single quotes). The following example queries the common name and the ADS path for any directory object residing in the container "OU=Enterprise-Minds,CN=Vancouver" in the Enterprise-Minds directory.

SELECT * FROM OPENQUERY(ADAM,
'SELECT cn, ADsPath FROM ''LDAP://Enterprise-Minds/OU=Enterprise-Minds,
CN=Vancouver'' ')

The LDAP dialect consists of four parts, each separated by a semicolon. The first part specifies the directory and the directory container, the second part the filter, the third part the list of attributes to return and the last part the scope of the search. The scope part can have three values - Base, OneLevel and SubTree. Base searches only the directory path that you specify. OneLevel searches the immediate children of the directory path that you specify. And SubTree searches all the descendants of the directory path that you specify. The following example returns the same information as the first SQL dialect example - the list of all group objects:

SELECT * FROM OPENQUERY(ADAM,
'<LDAP://Enterprise-Minds/OU=Enterprise-Minds,CN=Vancouver>;
(objectClass=group);cn;subtree')

The next example returns the same information as the second SQL dialect example - the common name and the ADS path of all directory objects:

SELECT * FROM OPENQUERY(ADAM,
'<LDAP://Enterprise-Minds/OU=Enterprise-Minds,CN=Vancouver>;;
cn,ADsPath;subtree')

You can find more information about the possible filter syntaxes at the following article. The filter syntax applies for both dialects with the difference that the values need to be put under single quotes for the SQL dialect. For example you can see that the value group in the SQL dialect example is under single quotes (double single quotes for escape sequencing) while it is not for the LDAP dialect example.

How to query Indexing Server catalogs?

Please refer to the following article for a detailed explanation on how to query Indexing Server catalogs. The following example queries the file name, path and the virtual path for all files in the linked Web Indexing Server catalog.

SELECT * FROM OPENQUERY(WEBCATALOG, 'SELECT FileName, 
Path, VPath FROM SCOPE()')

The next example queries for all the files which contain the value "default" and are residing under the "/Info" virtual directory and all its sub directories. It returns for all matches the file name, path and virtual path.

SELECT * FROM OPENQUERY(WEBCATALOG, 'SELECT FileName, Path, VPath FROM 
SCOPE(''DEEP TRAVERSAL OF("/Info")'') WHERE CONTAINS(FileName,''default'') ')

Please note that the value in the SCOPE function is under two single quotes for escape sequencing, while the value of the DEEP TRAVERSAL OF function is under double quotes, according to the Indexing Server SQL syntax. As shown you can create very complex queries.

How to query Excel spreadsheets?

All worksheets present in a linked Excel spreadsheet are shown as a tables. Note that all the table names show at the end a $ sign. Also if the worksheet name has spaces in it, you see the table name surrounded by single quotes which you always drop in your query. The table name in your query string needs to be surrounded by square brackets. The following example queries for all entries in the worksheet called Summary.

SELECT * FROM OPENQUERY(Books, 'SELECT * FROM [Summary$]')

It is important that the Excel spreadsheet is not open in Excel, otherwise you will get the following error:

Server: Msg 7399, Level 16, State 1, Line 1
OLE DB provider 'Microsoft.Jet.OLEDB.4.0' reported an error.
The provider did not give any information about the error.
OLE DB error trace [OLE/DB Provider 'Microsoft.Jet.OLEDB.4.0'
IDBInitialize::Initialize returned 0x80004005: The provider
did not give any information about the error.].






    摘要:

Introduction

This article provides two files that contain a Membership provider and a Role provider for ASP.NET v2.0.

Microsoft provides a Membership provider in the framework but only for SQL Server. The class does not seem to work for MySQL so I decided to write a new provider from the ODBC provider sample code included in the framework SDK.

How to use it

To use these classes, you will need the latest MySQL .NET Connector. You migh    (全文共9214字)——点击此处阅读全文




 Learning  C#

       C# is a language with the features of C++, programming style like Java and rapid application model of BASIC. If you already know the C++ language, it will take you less than an hour to quickly go through the syntax of C#. Familiarity with Java will be a plus, as Java program structure, the concept of packages and garbage collection will definitely help you learn C# more quickly. So while discussing C# language constructs, I will assume, you know C++.

This article discusses the C# language constructs and features using code examples, in a brief and comprehensive way, so that you just by having a glance at the code, can understand the concepts.

Note: This article is not for C# gurus. There must be some other beginner's articles on C#, but this is yet another one.

Following topics of C# language are discussed:

  • Program structure
  • Namespaces
  • Data types
  • Variables
  • Operators and expressions
  • Enumerations
  • Statements
  • Classes and structs
  • Modifiers
  • Properties
  • Interfaces
  • Function parameters
  • Arrays
  • Indexers
  • Boxing and unboxing
  • Delegates
  • Inheritance and polymorphism

Following are not discussed:

  • Things which are common in C++ and C#.
  • Concepts like garbage collection, threading, file processing etc.
  • Data type conversions
  • Exception handling
  • .NET library

Program structure

Like C++, C# is case-sensitive. Semi colon (;) is the statement separator. Unlike C++, there are no separate declaration (header) and implementation (CPP) files in C#. All code (class declaration and implementation) is placed in one file with extension cs.

Have a look at this Hello world program in C#.

using System;

namespace MyNameSpace

{

class HelloWorld

{

    static void Main(string[] args)

    {

        Console.WriteLine ("Hello World");

     }

}

}

Everything in C# is packed into a class and classes in C# are packed into namespaces (just like files in a folder). Like C++, a main method is the entry point of your program. C++'s main function is called main whereas C#'s main function starts with capital M and is named as Main.

No need to put a semi colon after a class block or struct definition. It was in C++, C# doesn't require that.

Namespace

Every class is packaged into a namespace. Namespaces are exactly the same concept as in C++, but in C# we use namespaces more frequently than in C++. You can access a class in a namespace using dot (.) qualifier. MyNameSpace is the namespace in hello world program above.

Now consider you want to access the HelloWorld class from some other class in some other namespace.

using System;

namespace AnotherNameSpace

{    

    class AnotherClass

    {

        public void Func()

        {

            Console.WriteLine ("Hello World");

        }

    }

}

Now from your HelloWorld class you can access it as:

using System;

using AnotherNameSpace; // you will add this using statement

namespace MyNameSpace

{

class HelloWorld

{

    static void Main(string[] args) 

    { 

        AnotherClass obj = new AnotherClass(); 

        obj.Func();

    }

}

}

In .NET library, System is the top level namespace in which other namespaces exist. By default there exists a global namespace, so a class defined outside a namespace goes directly into this global namespace and hence you can access this class without any qualifier.

You can also define nested namespaces.

Using

The #include directive is replaced with using keyword, which is followed by a namespace name. Just as using System as above. System is the base level namespace in which all other namespaces and classes are packed. The base class for all objects is Object in the System namespace.

Variables

Variables in C# are almost the same as in C++ except for these differences:

  1. Variables in C# (unlike C++), always need to be initialized before you access them, otherwise you will get compile time error. Hence, it's impossible to access an un-initialized variable.
  2. You can't access a “dangling” pointer in C#.
  3. An expression that indexes an array beyond its bounds is also not accessible.
  4. There are no global variables or functions in C# and the behavior of globals is achieved through static functions and static variables.

Data types

All types of C# are derived from a base class object. There are two types of data types:

  1. Basic/ built-in types
  2. User-defined types

Following is a table which lists built-in C# types:

Type Bytes Description
byte 1 unsigned byte
sbyte 1 signed byte
short 2 signed short
ushort 2 unsigned short
int 4 signed integer
uint 4 unsigned integer
long 8 signed long
ulong 8 unsigned long
float 4 floating point number
double 8 double precision number
decimal 8 fixed precision number
string  

  Unicode string
char  

  Unicode char
bool true, false boolean

Note: Type range in C# and C++ are different, example, long in C++ is 4 bytes, and in C# it is 8 bytes. Also the bool and string types are different than those in C++. bool accepts only true and false and not any integer.

User defined types includes:

  1. Classes
  2. Structs
  3. Interfaces

Memory allocation of the data types divides them into two types:

  1. Value types
  2. Reference types

Value types

Values types are those data types which are allocated in stack. They include:

  • All basic or built-in types except strings
  • Structs
  • Enum types

Reference types

Reference types are allocated on heap and are garbage collected when they are no longer being used. They are created using new operator, and there is no delete operator for these types unlike C++ where user has to explicitly delete the types created using delete operator. In C#, they are automatically collected by garbage collector.

Reference types include:

  • Classes
  • Interfaces
  • Collection types like Arrays
  • String

Enumeration

Enumerations in C# are exactly like C++. Defined through a keyword enum.

Example:

enum Weekdays

{

    Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday

}

Classes and structs

Classes and structs are same as in C++, except the difference of their memory allocation. Objects of classes are allocated in heap, and are created using new, where as structs are allocated in stack. Structs in C# are very light and fast data types. For heavy data types, you should create classes.

Examples:

Collapse
struct Date

{

    int day;

    int month;

    int year;

}

        

class Date

{

    int day;

    int month;

    int year;

    string weekday; 

    string monthName;

    public int GetDay()

    { 

        return day;

    }

    public int GetMonth() 

    { 

        return month;

    }

    public int GetYear() 

    { 

        return year;

    }

    public void SetDay(int Day) 

    { 

        day = Day ;

    }

    public void SetMonth(int Month)

    {

        month = Month;

    }

    public void SetYear(int Year)

    { 

        year = Year;

    }

    public bool IsLeapYear()

    {

        return (year/4 == 0);

    }

    public void SetDate (int day, int month, int year)

    {

    }

    ...

}

Properties

If you are familiar with the object oriented way of C++, you must have an idea of properties. Properties in above example of Date class are day, month and year for which in C++, you write Get and Set methods. C# provides a more convenient, simple and straight forward way of accessing properties.

So above class can be written as:

Collapse
using System;

class Date

{

    public int Day{

        get {

            return day; 

        }

        set {

            day = value; 

        }

    }

    int day;

    public int Month{

        get { 

            return month;

        }

        set {

            month = value; 

        }

    }

    int month;

    public int Year{

        get { 

            return year;

        }

        set {

            year = value;

        }

    }

    int year;

    public bool IsLeapYear(int year)

    {

        return year%4== 0 ? true: false; 

    }

    public void SetDate (int day, int month, int year)

    {

        this.day = day;

        this.month = month;

        this.year = year;

    }

}

Here is the way you will get and set these properties:

class User

{

   public static void Main()

   { 

        Date date = new Date(); 

        date.Day = 27; 

        date.Month = 6; 

        date.Year = 2003;

        Console.WriteLine

         ("Date: {0}/{1}/{2}", date.Day, date.Month, date.Year);

    }

}

Modifiers

You must be aware of public, private and protected modifiers that are commonly used in C++. I will here discuss some new modifiers introduced by C#.

readonly

readonly modifier is used only for the class data members. As the name indicates, the readonly data members can only be read, once they are written either by directly initializing them or assigning values to them in constructor. The difference between the readonly and const data members is that const requires you to initialize with the declaration, that is directly. See example code:

class MyClass

{

    const int constInt = 100; //directly

    readonly int myInt = 5; //directly

    readonly int myInt2;

    

    public MyClass()

    {

        myInt2 = 8;        //Indirectly

    }

    public Func()

    {

        myInt = 7; //Illegal

        Console.WriteLine(myInt2.ToString());

    }

    

}

sealed

sealed modifier with a class don't let you derive any class from it. So you use this sealed keyword for the classes which you don't want to be inherited from.

sealed class CanNotbeTheParent

{

    int a = 5;

}

unsafe

You can define an unsafe context in C# using unsafe modifier. In unsafe context, you can write an unsafe code, example: C++ pointers etc. See the following code:

public unsafe MyFunction( int * pInt, double* pDouble)

{

    int* pAnotherInt = new int;

    *pAnotherInt  = 10;

    pInt = pAnotherInt;

    ...

    *pDouble = 8.9;    

}

Interfaces

If you have an idea of COM, you will immediately know what I am talking about. An interface is the abstract base class containing only the function signatures whose implementation is provided by the child class. In C#, you define such classes as interfaces using the interface keyword. .NET is based on such interfaces. In C#, where you can't use multiple class inheritance, which was previously allowed in C++, the essence of multiple inheritance is achieved through interfaces. That's your child class may implement multiple interfaces.

Collapse
using System;

interface myDrawing

{

    int originx

    {

        get;

        set;

    }

    int originy

    {

        get;

        set;

    }

    void Draw(object shape);            

}

class Shape: myDrawing

{

    int OriX;

    int OriY;

    

    public int originx

    {

        get{

            return OriX;

        }

        set{

            OriX = value;

        }

    }

    public int originy

    {

        get{

            return OriY;

        }

        set{

            OriY = value;

        }

    }

    public void Draw(object shape)

    {

        ... // do something 

    }

    

    // class's own method

    public void MoveShape(int newX, int newY)

    {

    .....

    }        

    

}

Arrays

Arrays in C# are much better than C++. Arrays are allocated in heap and thus are reference types. You can't access an out of bound element in an array. So C# prevents you from that type of bugs. Also some helper functions to iterate array elements are provided. foreach is the statement for such iteration. The difference between the syntax of C++ and C# array is:

  • The square brackets are placed after the type and not after the variable name
  • You create element locations using new operator.

C# supports single dimensional, multi dimensional, and jagged arrays (array of array).

Examples:

int[] array = new int[10]; // single-dimensional array of int

for (int i = 0; i < array.Length; i++) 

    array[i] = i; 

int[,] array2 = new int[5,10]; // 2-dimensional array of int

array2[1,2] = 5;

int[,,] array3 = new int[5,10,5]; // 3-dimensional array of int

array3[0,2,4] = 9;

int[][] arrayOfarray = new int[2]; // Jagged array - array of array of int

arrayOfarray[0] = new int[4]; 

arrayOfarray[0] = new int[] {1,2,15};

Indexers

Indexer is used to write a method to access an element from a collection, by straight way of using [], like an array. All you need is to specify the index to access an instance or element. Syntax of Indexer is same as that of class properties, except they take the input parameter, that is the index of the element.

Example:

Note: CollectionBase is the library class used for making collections. List is the protected member of CollectionBase which stores the collection list.

class Shapes: CollectionBase 

{ 

    public void add(Shape shp)

    { 

        List.Add(shp);

    }

    //indexer

    public Shape this[int index]

    { 

        get { 

            return (Shape) List[index];

        } 

        set {

            List[index] = value ;

         }

     }

}

Boxing/Unboxing

The idea of boxing is new in C#. As mentioned above, all data types, built-in or user defined, are derived from a base class object in the System namespace. So the packing of basic or primitive type into an object is called boxing, whereas the reverse of this known as unboxing.

Example:

class Test

{

   static void Main() 

   {

      int myInt = 12;

      object obj = myInt ;      // boxing

      int myInt2 = (int) obj;   // unboxing

   }

}

Example shows both boxing and unboxing. An int value can be converted to object and back again to int. When a variable of a value type needs to be converted to a reference type, an object box is allocated to hold the value, and the value is copied into the box. Unboxing is just the opposite. When an object box is cast back to its original value type, the value is copied out of the box and into the appropriate storage location.

Function parameters

Parameters in C# are of three types:

  1. By-Value/In parameters
  2. By-Reference/In-Out parameters
  3. Out parameters

If you have an idea of COM interface and it's parameters types, you will easily understand the C# parameter types.

By-Value/In parameters

The concept of value parameters is same as in C++. The value of the passed value is copied into a location and is passed to the function.

Example:

SetDay(5);

...

void SetDay(int day) 

{ 

    ....

}

By-Reference/In-Out parameters

The reference parameters in C++ are passed either through pointers or reference operator &. In C# reference parameters are less error prone. Reference parameters are also called In-Out parameters because you pass a reference address of the location, so you pass an input value and get an output value from that function.

You can not pass an un-initialized reference parameter into a function. C# uses a keyword ref for the reference parameters. You also have to use keyword ref with an argument while passing it to a function demanding reference parameter.

Example:

int a= 5;

FunctionA(ref a); // use ref with argument or you will get compiler error

Console.WriteLine(a); // prints 20 
void FunctionA(ref int Val)

{

    int x= Val; 

    Val = x* 4;    

}

Out parameter

Out parameter is the parameter which only returns value from the function. The input value is not required. C# uses a keyword out for the out parameters

Example:

    int Val;

    GetNodeValue(Val);</