Re[2]: Проблема с #import ..... а может и не с ним
От: AndyCyborg Россия N/A
Дата: 17.05.04 09:40
Оценка:
Здравствуйте, Vi2, Вы писали:

День добрый. Приятен и вместе с тем обнадеживает тот факт, что к проблеме прикоснулись Уважаемые и Почтенные люди здешних мест. Спасибо !

Я потратил некоторое время на решение этой делемы до обращения с вопросом в форум. Вообще странно: впечатление, будто до меня ранее никто в это г... не наступал. Ладно, это лирика.

Вот что интересно. Предложенная в нижеследующем примере инструкция

Vi2>import "msado15.idl";  // need ADO


самим microsoft не рекомендуется. Вернее ... может не во всех случаях это нерабочий вариант, но если в проекте будет генериться прокси/стаб объект, то это точно не скомпилится. Нужно действовать через некий файл посредник. Они (MS_guys) это делают вот как:

import "oaidl.idl";
import "ocidl.idl";
import "helper.idl";    // import ADO thru helper IDL file


Теперь что из себя представляет "helper.idl". А это вот что:

import "msado15.idl";


И все. Но ...... нужен еще один файлик. Вот этот — helper.h:

#ifndef HELPER_H
#define HELPER_H

struct _Recordset;

    #if !defined(__cplusplus) || defined(CINTERFACE)
        typedef struct _Recordset _Recordset;
    #endif

#endif


Как видно, он исполнен в стиле VC 6.0, но это не важно. Важно, что они сами используют и рекомендуют именно такую технику. Вот собсна Было бы просто суппер, если бы все эти хитрые штучки были бы собраны однажды в одном месте, а не вот так с потом и кровью собирались каждым. Это взято из рекомендуемого ими же примера, который называется Atl2ado и может быть скачан с ms-сайта.

Кстати там же (в этом проекте) есть небольшой .txt, комментирующий происходящее, и вот что там в частности написано:



ATL2ADO.exe is a sample that demonstrates how to create a simple ATL COM object
that returns a disconnected ADO recordset. The sample also includes a Visual
Basic client that uses the ADO _Recordset returned from the ATL COM Server. The
Visual Basic client can change the record data and use the UpdateBat method
provided by the server to save changes to the database. After extracting the
files, build the Visual C++ project first to register the COM Objects, and then
use Visual Basic 6.0 to build the client program. The client and server can be
distributed to different computers on the network.

ATL2ADO.exe is a sample that demonstrates a minimal three-tiered Database
Application using ADO 2.0. An ATL server in the middle tier returns a read/write
disconnected recordset to a Visual Basic client for presentation. The Visual
Basic client can change the data and send it to the server to be updated. The
business logic is located in the COM server. The ATL COM server then updates the
Database tier.

The sample also shows how to build the proxy/stub DLL that is used to marshal the
recordset. The sample includes an Access .mdb file that you can use with Access
and SQL to build the student table that you can use with SQL Server. Use the
following query with the GradYear parameter supplied by the Visual Basic client:
"SELECT * FROM Student WHERE GradYear > ?"

Build the Visual C++ project with Visual C++ 6.0. This will create and register
the server and the proxy/stub dll. Build the Visual Basic project with Visual
Basic version 6.0. You can build the server on one computer and the client on
another computer on the same network. Copy the included Access database:
ADOSTUDENT.MDB to c:\test (or change the connection string in the source file).

The sample server was created with the ATL COM AppWizard as an .exe server. A
simple object ( r1DisRS ) was inserted. The following additions were made to the
.idl file:

1. Import helper.idl. The file name "helper.idl" is arbitrary. "helper.idl"
consists of one line: import msado15.idl. You must import ADO indirectly to
successfully build the proxy/stub DLL. Otherwise, MIDL gives you compiler
errors.

2. Add the following three methods to the interface:
getRS([in,optional,defaultvalue(88)] short GY, [out, retval]_Recordset **ppRS);
ConnString([in] BSTR newVal);
UpdateBat( _Recordset *ppRS);

3. In the Library section of the .idl, import the ADO DLL.

You must also create a file helper.h with the following contents:

struct _Recordset;
#if !defined(__cplusplus) || defined(CINTERFACE)
typedef struct _Recordset _Recordset;
#endif

ADO is imported thru the file stdAfx.h with the following two lines:

#undef EOF // Necessary for EOF collision.
#import "msado15.dll" no_namespace // Correct place to import ADO.




Это не все, а лишь, как мне показалось, относящийся к проблеме отрывок.



Vi2>Здравствуйте, KAndy, Вы писали:


Vi2>Дело в том, что import и importlib работают в паре. Т.е. есть две последовательности определения интерфейсов (или других типов):

Vi2>1. import...interface...importlib. Пример


Я вот не сомневаюсь в этих словах, но где описано это, что именно такая последовательность и такая связка. г_д_е э_т_о н_а_п_и_с_а_н_о ??? Книжка, ссылка, статья — хотел бы я очень то писание прочесть.


Vi2>
Vi2>import "msado15.idl";  // need ADO
Vi2>...
Vi2>interface Ixxx : IDispatch {
Vi2>...
Vi2>    [id(2),helpstring("method upload")] HRESULT upload([in] _Recordset* rs);
Vi2>...
Vi2>library XXXLib
Vi2>{
Vi2>...
Vi2>importlib("x:\program files\common files\system\ado\msado15.dll");  // need ADO
Vi2>

Vi2>msado15.idl определяет тип _Recordset в определении типа Ixxx и маршаллируется с помощью msado15.dll

Vi2>Здесь, очевидно, есть трудности. Наверное, это ошибка в MIDLе (или еще где), что интерфейс семантически разбирается до его использования в блоке library, в котором и определяется тип из некоей TLB. Но ничего не поделаешь



Да, это очень драматичное рассуждение !



Vi2>2. importlib...interface

Vi2>
Vi2>library XXXLib
Vi2>{
Vi2>...
Vi2>importlib("x:\program files\common files\system\ado\msado15.dll");  // need ADO
Vi2>...
Vi2>interface Ixxx : IDispatch {
Vi2>...
Vi2>    [id(2),helpstring("method upload")] HRESULT upload([in] _Recordset* rs);
Vi2>

Vi2>msado15.dll определяет тип _Recordset в определении типа Ixxx и маршаллируется с помощью msado15.dll
Vi2>

Vi2>

KA>>но в таком случае две инструкции #import конфликтуют, точнее на этапе компиляции возникает многократная
KA>>Если же вместо друх строк:
Vi2>

KA>>    #import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")
KA>>    #import "C:\Prog\SQL_XP\DataPipe\Debug\DataPipe.dll" no_namespace rename("EOF", "adoEOF")
Vi2>

KA>> оставить одну вида:
Vi2>
KA>>    #import "C:\Prog\SQL_XP\DataPipe\Debug\DataPipe.dll" rename("EOF", "adoEOF")
Vi2>

KA>> то возникают ошибки такие, будто не видно объявлений, которые нужны для работы с msado15.dll

Vi2>Это происходит потому, что твой IDL присваивает определения тех данных, которые упоминаются в нем (например, _Recordset) и не определяет тех, которые в нем не упоминаются. Это если не указано importlib. MIDLу просто напросто неоткуда брать информацию о таких типах, он и включает их в создаваемую TLB. OLE View показывает это хорошо, да и #import тоже.


Хорошо, пусть он их не включает и ему их не хватает. Но если оставить строку

#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")


то тут же получаем множественную ошибку связанную с повторным определением типов. Я вроде писал об этом в первом свое посте. Вот меня что смущается то на самом деле.

Какая-то странная ситуация. Вся странность ... видимо произрастает из не полного понимания того, что, куда и когда включается, а что нет.
Вот если в своем IDL файле я включаю через import и через importlib файлы, относящиеся к ado, то нужно ли мне потом в других проектах, где подключаю _свой_ COM-объект, также импортить адошные либы ??? Ведь в мой они по идее уже включены или я сурово заблуждаюсь ??? Где, где все это расписано ? Есть такие книги ? В MSDN что-то я не обнаружил исчерпывающих объяснений — может хреново искал ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.