分类 ‘PDF’ 的归档

浏览器中显示PDF

2009/03/29
使用.NET 向浏览器写入二进制文件 – 相关参考资料 – pdf之家 pdf阅读器格式文件下载
http://www.haopdf.cn/viewthread-2263.html

使用.NET 向浏览器写入二进制文件

admin 发表于: 2008-9-07 10:22 来源: pdf之家

本例演示了如何从文件中检索二进制数据,然后如何使用 ASP.NET 和 Visual C# 将该数据写出到浏览器中。尽管此演示使用的是 Adobe Acrobat (.pdf) 文件(Web 应用程序开发人员常使用这种文件),但您也可以对其他二进制文件格式使用此过程。

1、确保要查看 .aspx 页的客户端计算机上已安装了 Adobe Reader,以便浏览器能够正确读取并呈现二进制数据。可以从 Adobe 网站下载 Adobe Acrobat Reader:

http://www.chinese-s.adobe.com/main.html (http://www.adobe.com)
2、确保将您的页面添加到项目中在上一节中添加的 .pdf 文件所在的级别。这一点非常重要,因为代码最初引用 .pdf 文件时采用相对路径。

在页面的Page_Load 事件中,加入以下代码:

private void Page_Load(object sender, System.EventArgs e)
…{
//Set the appropriate ContentType.
Response.ContentType = “Application/pdf”;
//Get the physical path to the file.
string FilePath = MapPath(“acrobat.pdf”);
//Write the file directly to the HTTP content output stream.
Response.WriteFile(FilePath);
Response.End();
}

Java技巧:怎样从servlet打开一个非html文件(如PDF) – 相关参考资料 – pdf之家 pdf阅读器格式文件下载
http://www.haopdf.cn/viewthread-2281.html

Java技巧:怎样从servlet打开一个非html文件(如PDF)

admin 发表于: 2008-9-12 08:26 来源: pdf之家

1、摘要

Java Servlet 程序提供了一个简单的方式发送HTML文件到客户端浏览器。但是,现在一些站点提供了一些非HTML的存取文件,例如Adobe PDF,Microsoft Word, 和 Microsoft Excel 文件等。这篇文章以使用PDF和WORD为例子讲解怎样从SERVLET发送一个非HTML文件到客户端浏览器。事实上,通过本文,你可以通过MIME类型发送任何的格式的文件。同时,也能了解到通过SERVLET怎样与防火墙进行交互。

通过一个SERVLET在浏览器中打开一个文件,你只需简单的把这个文件加入到SERVLET的输出流中。尽管这么做看起来很简单,但是当你打开一个非HTML文件时你必须需要一些事情,例如二进制文件和多个文件的问题。

你可以通过一下方式得到SERVLET输出流:

ServletOutputStream out = res.getOutputStream();

互联网通过MIME(多用途网络邮件扩展)协议发送多部分,多媒体和二进制文件。在SERVLET的RESPONSE对象中,设置你想打开的文件的MIME类型是非常重要的。

2、MIME类型

客户端浏览器通过MIME类型来识别非HTML文件和决定用什么包容器来呈现这个数据文件。插件能够通过MIME类型来决定用什么方式来打开这些文件,当我们下载这些文件以后,我们通过浏览器就可以浏览这些文件了。

MIME类型很有用,他们允许浏览器通过内置技术处理不同的文件类型。

MIME类型对于一个PDF文件是application/pdf。当在SERVLET打开一个PDF文件时,你必须在RESPONSE最前面设置application/pdf:

// MIME type for pdf doc
res.setContentType( application/pdf);

打开一个WORD文档,你应该设置成application/msword:

// MIME type for MSWord doc
res.setContentType( application/msword );

对于EXCEL文档,使用MIME类型是application/vnd.ms-excel。如果需要的插件系统没有没有安装,浏览器会出现一个提示框,询问用户是否在当前位置打开还是保存到磁盘上。

3、内容部署

部署内容的HTTP response 头允许servlet指定文件类型的信息。使用这个头说明,你可以制定特定的方式来打开这个文件(不仅仅在浏览器中),而且它不应该自动的显示。你可以设置要保存的文件名。这个文件应该是对话框中显示的文件名。如果你不想指定文件名,你得到的是你的servlet同名的文件名称。

在SERVLET中你可以象下面的代码一样来设置头

res.setHeader(Content-disposition,
attachment; filename= +
Example.pdf);
// attachment – since we dont want to open
// it in the browser, but
// with Adobe Acrobat, and set the
// default file name to use.

如果你想打开一个WORD文件,应该如下做:

res.setHeader(Content-disposition,
attachment; filename +
Example.doc );

4、封装

剩下的工作就很简单了。你需要基于你想打开的文件的名字创建一个java.net.URL对象。这个字符串应该完整的指出这个文件的位置。举例说明:

String fileURL =
http://www.adobe.com/aboutadobe/careeropp/pdfs/adobeapp.pdf;

你的url字符串应该象http://www.gr.com/pub/somefile.doc或者

http://www.gr.com/pub/somefile.xls这个样子。

但是你必须确认你所打开的文件与你MIME类型中指定的文件类型一定要一致。

URL url = new URL ( fileURL );

5、防火墙

如果你的浏览器需要通过防火墙,最后的一件事情就是你需要担心的就是你的URL连接了。你需要找出一些你的代理服务器的一些信息,例如主机名称和端口号去与防火墙建立连接。如果你使用JAVA 2,你应该创建一个URL连接对象,设置以下的系统属性:

URLConnection conn = url.openConnection();

// Use the username and password you use to
// connect to the outside world
// if your proxy server requires authentication.
String authentication = Basic + new
sun.misc.BASE64Encoder().encode(username:password.getBytes());

System.getProperties().put(proxySet, true);

System.getProperties().put(proxyHost, PROXY_HOST); // your proxy host
System.getProperties().put(proxyPort, PROXY_PORT); // your proxy port
conn.setRequestProperty(Proxy-Authorization, authentication);

如果你使用JDK 1.1你可以不用建立系统属性。你应该用你的代理服务器信息创建JAVA.NET.URL对象。

url = new URL(http, PROXY_HOST,
Integer.parseInt(PROXY_PORT),
fileURL );
// assumes authentication is not required

6、实现

在开始读取你得文件的时候,你需要从URLConnection (or URL)对象中包含InputStream。

在以下的例子中,你用一个BufferedInputStream来限制这个InputStream。

如果你正在使用这个URLConnection,以下就是这样的代码:

BufferedInputStream  bis = new BufferedInputStream(conn.getInputStream());

如果你正在使用URL,那就象以下的代码:

BufferedInputStream  bis = new BufferedInputStream(url.openStream());

一旦做完以上工作,你只需简单的从输入流写出每一个字节到servlet的输出流中

BufferedOutputStream bos = new
BufferedOutputStream(out);

byte[] buff = new byte[2048];
int bytesRead;

// Simple read/write loop.
while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}

最后,在最后的模块中关闭这个流。

这个例子通过使用一个servlet的doPost方法来实现这个功能。

public void doPost(HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException
{
ServletOutputStream  out           =         res.getOutputStream ();

//—————————————————————
// Set the output datas mime type
//—————————————————————

res.setContentType( application/pdf);  // MIME type for pdf doc

//—————————————————————
// create an input stream from fileURL
//—————————————————————

String fileURL =
http://www.adobe.com/aboutadobe/careeropp/pdfs/adobeapp.pdf;

//————————————————————
// Content-disposition header – dont open in browser and
// set the Save As… filename.
// *There is reportedly a bug in IE4.0 which  ignores this…
//————————————————————
res.setHeader(Content-disposition,
attachment; filename= +=
Example.pdf);

//—————————————————————–
// PROXY_HOST and PROXY_PORT should be your proxy host and port
// that will let you go through the firewall without authentication.
// Otherwise set the system properties and use URLConnection.getInputStream().
//—————————————————————–
BufferedInputStream  bis = null;
BufferedOutputStream bos = null;

try {
URL url = new URL( http, PROXY_HOST,
Integer.parseInt(PROXY_PORT), fileURL  );

// Use Buffered Stream for reading/writing.
bis = new BufferedInputStream(url.openStream());
bos = new BufferedOutputStream(out);

byte[] buff = new byte[2048];
int bytesRead;

// Simple read/write loop.
while(-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
bos.write(buff, 0, bytesRead);
}

} catch(final MalformedURLException e) {
System.out.println ( MalformedURLException. );
throw e;
} catch(final IOException e) {
System.out.println ( IOException. );
throw e;
} finally {
if (bis != null)
bis.close();
if (bos != null)
bos.close();
}
}

7、总结

正如你所看到的,在一个servlet中打开一个非HTML是很简单的,甚至在一个防火墙之外。你可以使用同样的代码打开图像文件或者其他类型的多媒体文件,只要正确设置MIME类型。今天,在互联网上更多的信息都变得有效了,并且其中大量的信息是以非HTML类型存储的。相比之下,开发一个servlet来呈现非HTML文档是一件容易,方便的方式来提供给你的用户更多的信息。

在.NET中三种方式生成WSDL的方法_wanghero_猫扑博客
http://i.mop.com/wanghero/blog/2006/05/11/4247826.html
WSDL是一个XML格式用以描述怎样调用具体的Web Service,Web Service提供什么样的Service等等。

在.NET中有三种方式生成WSDL:

1.在Web Service的URL后面加上WDSL需求,如下:

http://localhost/webExamples/simpleService.asmx?WSDL

2.使用disco.exe。在命令行中写下如下的命令:

disco http://localhost/webExamples/simpleService.asmx

3.使用System.Web.Services.Description命名空间下提供的类

每个 WSDL 文件的根元素都是 <definitions>,必须在其中提供服务的完整描述。首先,必须在 <definitions> 元素中提供各种名称空间的声明。

<definitions> 元素包含一个或多个 < portType > 元素,每个元素都是一系列 operation。可以将单个portType元素看作是将各种方法组成类的一个逻辑分组。应该将每个Types称为服务,因此整个 WSDL 文件将成为一个服务集合。

在每个服务内可以有几个方法或者 operation,WSDL 通过 <operation> 元素来引用它们。

下面是一个最简单的WSDL例子

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<definitions name=”MobilePhoneService”
targetNamespace=”www.mobilephoneservice.com/MobilePhoneService-interface
xmlns=”http://schemas.xmlsoap.org/wsdl/
xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns=”http://www.mobilephoneservice.com/MobilePhoneService
xmlns:xsd=”http://www.w3.org/1999/XMLSchema“>

<portType name=”MobilePhoneService_port”>
<operation name=”getListOfModels “>
…….
…….
</operation>

<operation name=”getPrice”>
…….
…….
</operation>
</portType>
</definitions>

Sample 1

定义好操作(或方法)以后,现在需要指定将向它们发送和从它们返回的参数。在 WSDL 术语中,所有参数称为“消息”。认为您是在递送消息而结果得到返回的消息是有用的。方法调用是这样一种操作:它准备返回“消息”来响应进入的消息。

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<definitions name=”MobilePhoneService” targetNamespace=”http://www.mobilephoneservice.com/MobilePhoneService-interface
xmlns=”http://schemas.xmlsoap.org/wsdl/
xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns=”http://www.mobilephoneservice.com/MobilePhoneService
xmlns:xsd=”http://www.w3.org/1999/XMLSchema“>
<types>
<xsd:schema targetNamespace=”http://www.mobilephoneservice.com/MobilePhoneService
xmlns=”http://www.w3.org/1999/XMLSchema/“>
<xsd:complexType name=”Vector”>
<xsd:element name=”elementData” type=”xsd:String” />
<xsd:element name=”elementCount” type=”xsd:int” />
</xsd:complexType>
</xsd:schema>
</types>
<message name=”ListOfPhoneModels”>
<part name=”models” type=”tns:Vector”>
</message>
<message name=”PhoneModel”>
<part name=”model” type=”xsd:String”>
</message>
<message name=”PhoneModelPrice”>
<part name=”price” type=”xsd:String”>
</message>
<portType name=”MobilePhoneService_port”>
<operation name=”getListOfModels “>
<output message=”ListOfPhoneModels”/>
</operation>
<operation name=”getPrice”>
<Input message=”PhoneModel”/>
<output message=”PhoneModelPrice”/>
</operation>
</portType>
</definitions>

Sample 2

WSDL 的任务是定义或描述 Web 服务,然后提供一个对外部框架的引用来定义 WSDL 用户将如何实现这些服务。可以将这个框架当作 WSDL 抽象定义和它们的实现之间的“绑定(binding)”。

WSDL 将指定能够访问 Web 服务实际实现的 SOAP 服务器,并且从那时起 SOAP 的整个任务就是将用户从 WSDL 文件带到它的实现。

WSDL binding 元素包含您将用于绑定用途的外部技术的声明。因为正在使用 SOAP,所以这里将使用 SOAP 的名称空间。WSDL 术语中,对外部名称空间的使用称为 extensibility 元素。

… …
<portType name=”MobilePhoneService_port”>

… …
</portType>
<binding name=”MobilePhoneService_Binding” type=”MobilePhoneService_port”>
<soap:binding style=”rpc” transport=”http://schemas.xmlsoap.org/soap/http” />
<operation name=”getListOfModels “>
<soap:operation soapAction=”urn:MobilePhoneService” />
<input>
<soap:body encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” namespace=”urn:MobilePhoneService” use=”encoded” />
</input>
<output>
<soap:body encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” namespace=”urn:MobilePhoneService” use=”encoded” />
</output>
</operation>
</binding>

… …

Sample 3

WSDL 需要一个附加步骤来创建该 WSDL 文件的概要。WSDL 将该文件称为 implementation 文件,当在 UDDI 注册中心发布 Web 服务时,会使用它。

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<definitions name=”MobilePhoneService”
targetNamespace=”http://www.mobilephoneservice.com/MobilePhoneService
xmlns=”http://schemas.xmlsoap.org/wsdl/
xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns=”http://www.mobilephoneservice.com/MobilePhoneService
xmlns:xsd=”http://www.w3.org/1999/XMLSchema“>
<import location=”http://localhost:8080/wsdl/MobilePhoneService-interface.wsdl” namespace=http://www.mobilephoneserviceservice.com/MobilePhoneService-interface/>
<service name=”MobilePhoneService”>
<documentation> Mobile Phone Information Service </documentation>
<port binding=”MobilePhoneService_Binding” name=”MobilePhoneService_ServicePort”>
<soap:address location=”http://localhost:8080/soap/servlet/rpcrouter” />
</port>
</service>
</definitions>

Introducing SOAP

Dave Wraight Planet PDF Contributing Editor

March 18, 2004

Advertisement
Advertisement

SOAP or Simple Object Access Protocol has become a standard mechanism in the world of Web Services. Now what exactly does this mean? And how can I make use of it inside Acrobat?

The definition given by the governing standards body W3C (World Wide Web Consortium) is:

“SOAP is a lightweight protocol for exchange of information in a decentralized, distributed environment. It is an XML based protocol that consists of three parts: an envelope that defines a framework for describing what is in a message and how to process it, a set of encoding rules for expressing instances of application-defined datatypes, and a convention for representing remote procedure calls and responses. SOAP can potentially be used in combination with a variety of other protocols; however, the only bindings defined in this document describe how to use SOAP in combination with HTTP and HTTP Extension Framework.”

This is quite a mouthful, but essentially means that SOAP is a way for two computer programs to talk to each other using XML as the language and HTTP as the transport layer.

These two programs can be on the same network or across the other side of the planet using different hardware, software and operating systems. They can communicate because they have a common language: SOAP.

Before SOAP came on the scene there were several large vendors each with their own proprietary protocols (CORBA, RMI, COM/DCOM) and toolsets this made it very difficult to implement systems when the two systems didn’t talk the same language. SOAP promises to make these complications a thing of the past.

Now that we have a little bit better understanding of what SOAP is, the next question is how is it useful to me?

Illustrating The Point

Let’s say for example that you have a customer who wants to purchase some rare coins from your website. Since these coins are hard to find you don’t keep them in stock, instead you have a supplier that you purchase them from.

Your potential customer browses your list of coins making selections and adding them to their online shopping basket. Once they have finished browsing they want to purchase their selections and proceed to the checkout.

At the checkout page they discover that the coins that they have selected aren’t in stock and since your web site isn’t setup to automatically find available stock you aren’t able to inform the customer of the expected delivery dates.

Rather than lose a potential sale, you decide to investigate a better way to do business.

This is where Web Services & SOAP steps in. Imagine instead that your web server was able to talk to the computer of your supplier(s) and find out what stock they have and the exact delivery details, also imagine that this could be done on demand and in real-time.

All that’s required to make this happen is for the supplier(s) to create a web service for their distributors (namely your web site) that let’s you find out what stock they have and also when it can be delivered.

In the above picture the supplier’s web service is asked about a product’s availability, delivery and exact price, it returns this information in the same structured way as it was asked for, in XML.

Your web site is now able to immediately inform the customer what is available, how much it will cost and when they can expect delivery.

Acrobat And SOAP

Right about now your probably wondering how is Acrobat involved in this loop? Well it turns out that Acrobat version 6 now supports SOAP through Javascript.

This means that you can build fully interactive and graphically designed PDF documents that have built in smarts for talking to Web Services. This is great since you can combine everything that’s great about PDF with the ability to do real business with Web Services.

To really illustrate how this works I’ve created a PDF form with two examples to demonstrate how to make use of web services/SOAP. The first free web service allows you to convert between different currencies for any currency in the world and the second web service gives you the postcode for any australian city name.

There are several things going on in the background after you press the ‘GO’ button. The first thing to happen is that Javascript is called upon to create a connection between the PDF form and the Web Service. This connection is made using SOAP.

This connection is referred to as an End Point connection and generally requires a URI (Uniform Resource Indentifier). At the other end of the connection is the Web Services Definition Language (WSDL) file for the web service. This file describes the parameters and responses the web service requires and allows other users to know how to operate the web service.

After a connection has been made between Acrobat and the Web Service a Javascript Object is created representing the web service, this object can then be used to pass information to the web service in the hope it will return the information we are chasing.

The Process

As the diagram below illustrates the following five steps are happening:

  1. Connection Object created between Acrobat and the Web Service
  2. Web Service Functions called
  3. User entered data taken from Form text fields and wrapped as XML fragments
  4. Web Service process request and returns response wrapped in XML
  5. Acrobat automatically formats the raw XML data in human readable format

The potential for Web Services & SOAP to really help businesses communicate is enormous. Couple this with the platform independance, stable and secure format that we have grown to known from PDF and it’s a perfect match.

Adobe Forums – WSDL-Data Binding Issue
http://www.adobeforums.com/webx/.3c057542/0
Topic

WSDL-Data Binding Issue

Saritha Mikkilineni – 01:54pm Nov 30, 2007 Pacific

I am very very new to Adobe LiveCycle ES (Beginner). I am having problems binding the Response to the Fields on the xdp form.

I was successfully able to invoke the Webservice. findAccount webservice takes ssn as input and returns xml string as response. I need to bind the xml string response to the xsd schema fields on the form (xdp). How can I do it?

Below are the detail steps I created

1.open new template in Designer 7.0
2.from the Data View, added new XML Schema file
3.Designed the form using the XML Schema elements
4.again from the Data View, invoked the WSDL ( findAccount WS. Ssn – as input. XML string as output)
5.When I hit the “Button” by giving the input, I see the response in the output box. But, I need the output displayed on the from fields which I binded it to the xml schema .


Reply To This Discussion | Back to Topic List | Bookmark | Subscribe
To start a NEW discussion click on the Back to Topic List link and select Add Topic.
If you are in an archive forum please go up to the main topic list (archives are read only).

Messages

3 messages. Displaying 1 through 3.
First    Previous      Next  Last  Show All Messages
WorkflowUser - 7:13pm Nov 30, 07 PST (#1 of 3)

I assume your web service is returning data of type “xml” and not string
Once you do this store the xml data in a hidden text field. then get the raw value of this hidden text field. This is your xml. you can xpath into the xml data.
for more information check the javascript for acrobat documentation @
http://www.verydoc.com/documents/acrojsguide/index.htm
go to Page 258,you will find some examples on how to do it

Post Reply | Bookmark back to top

WorkflowUser - 6:49pm Dec 1, 07 PST (#2 of 3)

my earlier post indicated that your web service return xml type instead of string, this is not requried it can be of string type as well

Post Reply | Bookmark back to top

Saritha Mikkilineni - 7:20am Dec 4, 07 PST (#3 of 3)

Thanks for the response. This issue is resolved.

Post Reply | Bookmark back to top

To post a message, compose your text in the box below, then click on Post (below) to send the message.

A blank line starts a new paragraph. A line starting with ‘b ‘, ‘i ‘, ‘c ‘, ‘* ‘, ‘] ‘, or ‘> ‘ provides simple formatting. You may use links to previous messages. See the quick-edit help for more information.

Message:
Subscribe to this discussion by email


You cannot rewrite history, but you will have 30 minutes to make any changes or fixes after you post a message. Just click on the Edit button which follows your message after you post it.

read subscriptions | message center | forum search | knowledgebase search | help | preferences | logout
 / User to User Forums  / Adobe Product Forums  / Adobe LiveCycle Forums  / LiveCycle ES  / LiveCycle Designer ES

VC++获得当前系统时间的几种方案 zz – VC – zz
http://blog.chinaunix.net/u2/63021/showart_1099314.html
VC++获得当前系统时间的几种方案 zz
//方案— 优点:仅使用C标准库;缺点:只能精确到秒级
#include <time.h>
#include <stdio.h>
int main( void )
{
time_t t = time( 0 );
char tmp[64];
strftime( tmp, sizeof(tmp), “%Y/%m/%d %X %A 本年第%j天 %z”,
localtime(&t) );
puts( tmp );
return 0;
}
//方案二 优点:能精确到毫秒级;缺点:使用了windows API
#include <windows.h>
#include <stdio.h>
int main( void )
{
SYSTEMTIME sys;
GetLocalTime( &sys );
printf( “%4d/%02d/%02d %02d:%02d:%02d.%03d 星期%1d\n”
,sys.wYear,sys.wMonth,sys.wDay
,sys.wHour,sys.wMinute,sys.wSecond,sys.wMilliseconds
,sys.wDayOfWeek);
return 0;
}
//方案三,优点:利用系统函数
#include<stdlib.h>
#include<iostream>
using namespace std;
void main(){
system(“time”);
}
可以改变电脑的时间设定
方案4:
#include<iostream>
#include<ctime>
using namespace std;
int main()
{
time_t now_time;
now_time = time(NULL);
cout<<now_time;
return 0;
}
另一:_strdate(tempstr);
另二:
CString CTestView::GetTime()
{
CTime CurrentTime=CTime::GetCurrentTime();
CString strTime;
strTime.Format(“%d:%d:%d”,CurrentTime.GetHour(),  CurrentTime.GetMinute(),CurrentTime.GetSecond());
return strTime;
} language=VBScript>call ReplaceSubjectHTML_emote(592915)

精确获得时间
Win32   API函数库中已经为用户提供了一组用于高精度计时的底层函数,如果用户使用得当,计时精度可到1ms。这个计时精度,对于一般的实时系统控制完全可以满足要求。现将由BCB提供的重新封装后的一组与时间相关的主要接口函数(函数名、参数、功能与Win32API基本相同)说明如下:
1.DWORD   timeGetTime(void)
返回从Windows启动开始经过的毫秒数。最大值为2的32次方,约49.71天。
2.MMRESULT timeSetEvent(UINT   uDelay,UINT   uResolution,
LPTIMECALLBACK lpTimeProc, DWORD dwUser, UINT fuEvent)
该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数,成功后返回事件的标识代码,否则返回NULL.参数说明如下:
uDelay:以毫秒制定事件的周期。
UResolution:以毫秒指定延时的精度,数值越小定时器事件分辩率越高。缺省值为1ms.
LpTimeProc:指向一个回调函数。
DwUser:存放用户提供的回调数据。
FuEvent:指定定时器事件类型:TIME_ONESHOT:uDelay毫秒后只产生一次事件。
TIME_PERIODIC: 每隔uDelay毫秒周期性地产生事件。

3.MMRESULT   timeKillEvent(UINT   uTimerID)
该函数取消一个指定的定时器回调事件。uTimerID标识要取消的事件(由timeSetEvent函数返回的标识符)。如果定时器时间不存在则返回MMSYSERR_INVALPARAM。
void CALLBACK TimeProc(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2);
该函数是一个应用程序定义的回调函数,出现定时器事件时该函数被调用。TimeProc是应用程序定义的函数名的占位符。

使用该函数时要注意的是,它只能调用以下有限的几组API函数:
PostMessage,timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent,
midiOutShortMsg, midiOutLongMsg, OutputDebugString。同时也不要使用完成时间很长的API函数,程序尽可能简短。
使用以上一组函数就可以完成毫秒级精度的计时和控制(在BCB使用时要将头文件mmsystem.h加到程序中)。由于将定时控制精确到几毫秒,定时器事件将占用大量的CPU时间和系统资源,所以在满足控制要求的前提下,应尽量将参数uResolution的数值增大。而且定时器实时控制功能完成后要尽快释放。

COM组件的开发

VC OCX 打包CAB 网页发布全过程记录_Asp.net实例教程_Asp.net_网站开发
http://www.diybl.com/course/4_webprogram/asp.net/asp_netshl/2008111/96318.html

VC OCX 打包CAB 网页发布全过程记录

http://www.diybl.com/ 2008-1-11  网络 点击: [ 评论 ]
文章搜索:    【点击打包该文章】
【本站开通在线QQ讨论群】

第一次发布一个activeX控件,真的费了不少力气,主要是对发布的原理和过程不大清楚。在这里记下过程,以备后用和其它网友参考。

1,创建OCX:你要创建一个可用的OCX控件,并在本机测试通过。

2,打包CAB:WinCAB 是一种可视化的全新的CAB压缩包制作软件,它具有采用图形界面、支持分卷压缩、可制作具有自解包功能的CAB压缩包(*.EXE文件格式)等优秀功能, 这就从根本上解决了CAB压缩包的制作问题。需要注意的是在运行WinCAB.exe时,必须确保makecab.exe文件也在相同的目录下。


注:WinCAB在网上有很多下载,可以去百度搜,makecab.exe在系统盘windows\system32下。

一般来说,一个单独的OCX不需要INF也可以打成CAB发布,所以这里就不介绍INF文件了,想了解的话,去我文章下边的几个链接。


3,数字签名:做为测试,也可以不要数字签名。只需要在客户端PC的IE安全选项中,把级别调低或针对ACTIVEX设置调成enable。


关于证书和签名     -|zuiwanting 发表于 2006-5-24 9:58:00

[C#]利用反射调用COM组件 【中国IT软件知识库/大中华软件交易网】软件公司/软件开发人员社区论坛 软件项目交易网(软件外包、项目外包承接、软件供求交易、软件招标投标、投资融资合作)
http://www.ooreport.com/bbs/topicView.aspx?Id=90034

[C#]利用反射调用COM组件

最常见的调用com组件的方法就是添加对这个组件的引用,但是这会在最终可执行文件边生成一个伴随的dll如MyCom.Interop.dll等,这给程序的分发带来相当程度的不便,而且添加引用是我们只能引用某个特定版本的com组件,而我们往往无法确定程序所运行的机器上是否有相应版本的com组件,这可能造成我们的程序无法运行。我们要如何解决这个问题呢?
首先要解决com组件的版本问题,这就要求我们不直接使用clsid,而用ProgId来代替客户机上的com组件就可以解决相当程度的问题了,就是这么简单。
至于如何才能把那个可恶的dll文件给去掉,这就需要利用dotNet提供的反射功能了,我们一代码为例,这里我们假设有一个ProgId为”ReflectionCom.TestObj”的com组件,这个组件有唯一一个方法string SayHello(string AName):

using System;
using System.Reflection;

namespace TestConsole
{
class MainEntryPoint
{
static void Main(string[] args)
{
object[] oParams = new object[] { leafyoung };
object oComObj = Activator.CreateInstance(
Type.GetTypeFromProgID(
ReflectionCOM.TestObj));
object rez = oComObj.GetType().InvokeMember(SayHello,
BindingFlags.InvokeMethod,
null,
oComObj,
oParams);
Console.WriteLine(rez);
}

}

}

行了,我们就是怎么简简单单就可以调用com组件的任何功能了。
不过我们要看到这种方法的不足,由于这里用了迟绑定,因此我们无法让编译器做任何的类型检查工作,因此只有在运行时才能知道程序对错;而且,可以以这种方法调用的com组件必须实现IDispatch接口,也就是说必须是一个自动化组件,假如你要调用的组件是一个普通的com组件的话,那就一边哭去吧!呵呵

PRB: Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Affects
http://support.microsoft.com/default.aspx?scid=kb;en-us;308095

PRB: Creating STA Components in the Constructor in ASP.NET ASPCOMPAT Mode Negatively Affects Performance

This article was previously published under Q308095

SYMPTOMS

When you call apartment-threaded components from an ASP.NET page in ASPCOMPAT m…

When you call apartment-threaded components from an ASP.NET page in ASPCOMPAT mode, you may notice severe performance degradation.

CAUSE

If you use ASPCOMPAT mode (that is, if you use a page with the <%@ ASPCOMPAT=”t…

If you use ASPCOMPAT mode (that is, if you use a page with the <%@ ASPCOMPAT=”true” %> directive), ASP.NET runs those pages on an STA thread pool. However, Component Object Model (COM) components that are created at construction time are created before the request is scheduled to the single-threaded apartment (STA) thread pool and are therefore created from a multithreaded apartment (MTA) thread. In this scenario, you experience substantial performance degradation.

Most significantly, the same thread (host STA) executes all instances of apartment-threaded components that are created from MTA threads. This means that even though all users have a reference to their own instance of the COM component, all of the calls into these components are serialized to this one thread (only one call executes at a time).

Additionally, there is a smaller performance hit each time a call is made to the component from the Page events because of a thread switch. This is because the Page events are executed on a thread from the STA pool, but the COM component is still executed on the host STA (because the COM component was created from an MTA client). This thread switch also leads to other errors if you use impersonation. For more information, see the “References” section of this article.

RESOLUTION

If you are using ASPCOMPAT mode with STA components, only create COM components…

If you are using ASPCOMPAT mode with STA components, only create COM components from a method or one of the Page events (for example, Page_Load, Page_Init, and so on), and do not create these COM components at construction time.

For example, avoid a member declaration similar to the following, which creates the component at construction time:

Visual Basic .NET

<%@ Page Language="VB" ASPCOMPAT="TRUE" %>
<script runat="server">

Dim comObj As MyComObject = New MyComObject()

Public Sub Page_Load()
   comObj.DoSomething()
End Sub
</script>

Visual C# .NET

<%@ Page Language="C#" ASPCOMPAT="TRUE" %>
<script runat="server">

MyComObject comObj = new MyComObject();

public void Page_Load()
{
   comObj.DoSomething()
}
</script>

Visual J# .NET

<%@ Page Language="VJ#" ASPCOMPAT="TRUE" %>
<script runat="server">

MyComObject comObj = new MyComObject();

public void Page_Load()
{
  comObj.DoSomething();
}
</script>

Use the following code instead:

Visual Basic .NET

<%@ Page Language="VB" ASPCOMPAT="TRUE" %>
<script runat="server">

Dim comObj As MyComObject 

Public Sub Page_Load()
   comObj = New MyComObject()
   comObj.DoSomething()
End Sub

Visual C# .NET

<%@ Page Language="C#" ASPCOMPAT="TRUE" %>
<script runat="server">

MyComObject comObj;

public void Page_Load()
{
   comObj = new MyComObject();
   comObj.DoSomething();
}

Visual J# .NET

<%@ Page Language="VJ#" ASPCOMPAT="TRUE" %>
<script runat="server">

MyComObject comObj;

public void Page_Load()
{
  comObj = new MyComObject();
  comObj.DoSomething();
}
</script>

STATUS

This behavior is by design.

This behavior is by design.

REFERENCES

For additional information, click the article number below to view the article i…

For additional information, click the article number below to view the article in the Microsoft Knowledge Base:

325791 (http://support.microsoft.com/kb/325791/EN-US/ ) PRB: Access Denied Error Message Occurs When Impersonating in ASP.NET and Calling STA COM Components

APPLIES TO
  • Microsoft ASP.NET 1.1
  • Microsoft Visual Basic .NET 2003 Standard Edition
  • Microsoft Visual C# .NET 2003 Standard Edition
  • Microsoft ASP.NET 1.0
  • Microsoft Visual Basic .NET 2002 Standard Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft Visual J# .NET 2003 Standard Edition
  • Microsoft .NET Framework 1.1
Keywords:
kbhttpruntime kbinterop kbperformance kbprb kbreadme kbthread KB308095

CodeProject: Importing and Extending ActiveX Controls in .NET. Free source code and programming help
http://www.codeproject.com/KB/cs/importactivex.aspx

PRB: 灾难性故障错误使用 ActiveX 控件
http://support.microsoft.com/kb/189065/zh-cn

PRB: 灾难性故障错误使用 ActiveX 控件

本页

症状

从 Java, 试图使用 VisualC++ 生成 ActiveX 控件时试图运行 Java 应用程序时将看到以下错误: 错误: <0x8000ffff>…

从 Java, 试图使用 VisualC++ 生成 ActiveX 控件时试图运行 Java 应用程序时将看到以下错误:

错误: <0x8000ffff> 正在按任意键以继续 Catastrophic 失败

解决方案

当试图使用 ActiveX 控件作为自动化服务器, 您需要重写 IsInvokeAllowed 方法。 有关为什么此方法对被覆盖, 请参阅下面参考部分。 要…

当试图使用 ActiveX 控件作为自动化服务器, 您需要重写 IsInvokeAllowed 方法。 有关为什么此方法对被覆盖, 请参阅下面参考部分。

要解决该问题, 如下替代 IsInvokeAllowed 将 ActiveX 控件中:

BOOL CMyOleControl::IsInvokeAllowed (DISPID)
{

   // You can check to see if COleControl::m_bInitialized is FALSE
   // in your automation functions to limit access.
  return TRUE;
}

对于下面, 给定示例情况都将覆盖 Circ3ctl.cpp 文件中此方法并声明 Cir3ctl.h 文件中此虚函数。 还请确保重建并从 Java 使用之前注册控件。

状态

此行为是设计使然。

此行为是设计使然。

更多信息

复现行为的步骤 生成并注册 Circ3.ocx 示例随 VisualC++ 附带。 运行 JACTIVEX /javatlb circ3.ocx。 这将创建称…

复现行为的步骤

  1. 生成并注册 Circ3.ocx 示例随 VisualC++ 附带。
  2. 运行 JACTIVEX /javatlb circ3.ocx。 这将创建称为 circ3 % windir%\java\trustlib, 将包含相应 coclass, .java 文件对于 CIRC3.OCX 接口下一个文件夹。
  3. 如下创建 Java 应用程序并导入 ActiveX 控件:
    import com.ms.com.*;
    import circ3.*;
    
    public class circle
    {
       public static void main(String args[])
       {
          circle main = new circle();
          main.test();
       }
    }
    
    public void test()
    {
       _DCirc3 c  = null;
       c  = (_DCirc3) new Circ3();
       c.AboutBox();
    }
    
    }
  4. 生成 for Java 2.0 以使用附带 JVC x 或更高 Java 应用程序。 有关如何将此 JVC 与 VisualJ++, 请参阅下面参考部分。
  5. 将看到上面提到的错误消息。

参考

有关如何使用 ActiveX 控件用作自动化服务器, 请参阅下列 Microsoft 知识库文章: 146120  (http://support.micr...

有关如何使用 ActiveX 控件用作自动化服务器, 请参阅下列 Microsoft 知识库文章:

146120 (http://support.microsoft.com/kb/146120/EN-US/ ) HOWTO: 使用 OLE 控件作为自动化服务器

有关如何对 VisualJ++, 使用新 Jvc.exe 请参阅下列 Microsoft 知识库文章:

183712 (http://support.microsoft.com/kb/183712/EN-US/ ) 有关 SDK for Java HOWTO: 安装说明

这篇文章中的信息适用于:
  • Microsoft Java Virtual Machine
  • Microsoft Software Development Kit for Java 2.02
  • Microsoft Software Development Kit for Java 2.01
  • Microsoft Software Development Kit for Java 3.0
  • Microsoft Software Development Kit for Java 3.1
  • Microsoft Software Development Kit for Java 3.2
  • Microsoft Visual J++ 1.0 Standard Edition
  • Microsoft Visual J++ 1.1 Standard Edition
关键字:
kbprb KB189065 KbMtzh kbmt

CodeProject: OPC and .NET with COM Interoperability. Free source code and programming help
http://www.codeproject.com/KB/COM/opcdotnet.aspx

Sample Image

Abstract

In industrial automation, OPC (OLE for Process Control, see www.opcfoundation.org) is the primary COM component interface used to connect devices from different manufactures. The OPC standard is defined at ‘two different layers’ of COM/DCOM. First, as a collection of COM custom interfaces, and secondly as COM-automation compliant components/wrappers. For some reasons and applications, it is preferable to use the custom interface directly.

We will show you in this article how to access OPC servers with custom interfaces and how to write an OPC client in .NET.

The problem

The new Microsoft .NET Framework will provide some interoperability layers and tools to reuse a large part of the existing COM/ActiveX/OCX components, but with some strong limitations. While automation compliant COM objects will be nicely imported (as referenced COM objects inside Visual Studio .NET, or with the TLBIMP tool), pure custom COM interfaces will not work.

To understand the issues with COM custom interfaces and the .NET framework, we must first analyze, why automation components can be used immediately. Visual Studio .NET relies on the information found in a type-library for every imported COM component (e.g. the library generated by MIDL-compiler, named *.TLB). The problem is now, type libraries can only contain automation compliant information. So if we compile a custom-interface IDL file, the generated TLB misses very important type descriptions, especially the method call parameter size (e.g. of arrays). At the time of .NET Beta2, there’s unfortunately no tool (like ‘IDLIMP’) to import custom interface IDL files.

Example: Since the MIDL compiler does not propagate size_is information to the type library, the marshaler doesn’t know an array length and translates int[] to ref int.

One first solution would be to edit the assembly produced by TLBIMP (using ILDASM), and replace ref int with int[], and then compile IL back again with ILASM.

But if we look at some very custom IDL files, we also find methods with parameters like foo( int **arraybyref ) where arrays are passed by reference (caller allocates the memory)! Hand editing IL code won’t work here, there’s no marshaling signature for this. Currently, we must use one of two different workarounds:

  • Write a custom marshaler (e.g. in Managed C++)
  • Or the way we used, write a marshaling helper class (in C#)

The solution, first step

We have to rewrite our custom IDL file in a managed language code, here C#. Note this can be a very time consuming work! every method of all interfaces have to be coded in C#, and the critical (custom) parameters must be declared completely different. We found there’s often no way around the use of the special IntPtr type.

Let’s look at a sample method (from an OPC custom interface IDL):

Collapse
HRESULT AddItems(
  [in]                        DWORD            dwCount,
  [in,  size_is( dwCount)]    OPCITEMDEF     * pItemArray,
  [out, size_is(,dwCount)]    OPCITEMRESULT ** ppAddResults,
  [out, size_is(,dwCount)]    HRESULT       ** ppErrors    );

Redefined in C#, looks now like this:

Collapse
int AddItems(
  [In]       int       dwCount,
  [In]       IntPtr    pItemArray,
  [Out]  out IntPtr    ppAddResults,
  [Out]  out IntPtr    ppErrors );

As you can see, we loose many type information by declaring parameters as IntPtr!

Another point is the default exception mapping of .NET: as custom interface methods return HRESULT values, failed calls will be converted by the .NET marshaller to exceptions of type COMException. Further, some COM methods will also return other success codes besides S_OK, mainly S_FALSE. With the default mapping, this hint return value will be lost.

To bypass exception mapping, declare the interface with special signature attributes. See at the code below for the head of the final interface declaration:

Collapse
  [ComVisible(true), ComImport,
  Guid("39c13a54-011e-11d0-9675-0020afd8adb3"),
  InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IOPCItemMgt
  {
    [PreserveSig]
  int AddItems(
    [In]       int       dwCount,
    [In]       IntPtr    pItemArray,
    [Out]  out IntPtr    ppAddResults,
    [Out]  out IntPtr    ppErrors );
  ...

The solution, second step

To use the interfaces we declared as above, it is recommended to write some wrapper classes. But more important, this wrapper now has to do all the custom marshaling, e.g. for all IntPtr parameters. So the wrapper must reconstruct the information we lost. Managed marshaling code makes use of the framework services provided in the System.Runtime.InteropServices namespace, especially the Marshal class. We found the following methods as useful for this:

AllocCoTaskMem() FreeCoTaskMem() SizeOf() manage COM native memory (as pointed to by IntPtr)
StructureToPtr() PtrToStructure() DestroyStructure() marshaling of simple structures
ReadInt32() WriteInt32() Copy() read/write to native memory (also -Byte/Int16/Int64)
PtrToStringUni() StringToCoTaskMemUni() string marshaling
GetObjectForNativeVariant() GetNativeVariantForObject() conversions between VARIANT and Object
ThrowExceptionForHR() map HRESULT to exception and throw
ReleaseComObject() finally, release COM object

To get the idea, see a simplified excerpt for the sample method AddItems() we declared above – here we allocate native memory and marshal an array of structures into it:

Collapse
...
IntPtr ptrdef = Marshal.AllocCoTaskMem( count * sizedefinition );
int rundef = (int) ptrdef;
for( int i = 0; i < count; i++ )
  {
  Marshal.StructureToPtr( definitions[i], (IntPtr) rundef, false );
  rundef += sizedefinition;
  }

int hresult = itemsinterface.AddItems( count, ptrdef, ... );
  ...
int rundef = (int) ptrdef;
for( int i = 0; i < count; i++ )
  {
  Marshal.DestroyStructure( (IntPtr) rundef, typedefinition );
  rundef += sizedefinition;
  }
Marshal.FreeCoTaskMem( ptrdef );
...

Download

In the download package, you will find the complete interface declarations and a sample client application showing how to use them.

Please note:

  • First read the included whitepaper
  • To run this OPC client, you must have any OPC-DA 2.0 servers installed!

Useful links

OPC, the OPC logo, and OPC Foundation are trademarks of the OPC Foundation. .NET, the .NET logo, and Microsoft .NET are trademarks of the Microsoft Corporation.

Disclaimer

The information in this article & source code are published in accordance with the Beta2 bits of the .NET Framework SDK).

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

VISCOM .NET Team
Location: United States United States

Other popular COM / COM+ articles:

请问,在ASP下如何调用OCX控件,高分求救 Web 开发 / ASP – CSDN社区 community.csdn.net
http://topic.csdn.net/t/20020918/21/1035190.html

请问,在ASP下如何调用OCX控件,高分求救

kaney00(kaney00)2002-09-18 21:52:45 在 Web 开发 / ASP 提问

请问,在ASP下如何调用OCX控件??

顺便问一下,OCX控件的用法之类的,

请大家知道一点就说一点,多谢,

急,

!!!

问题点数:100、回复次数:10Top

Iamfish(呆鱼)回复于 2002-09-18 22:18:37 得分 10

ASP应该不能调用OCX控件。因为OCX控件是可视的!

就是ASP里面不能用MSGBOX一样。

可以调用ActivX   DllTop

kaney00(kaney00)回复于 2002-09-18 22:26:52 得分 0

啊,这样呀,

我对OCX都不熟悉,是一个朋友问我,他上网不方便,

所以,能不能请lamfish讲多一些关于OCX的东西,因为我刚才在网上找了一下,发现讲OCX的不多,

多谢!!!!!!Top

kaney00(kaney00)回复于 2002-09-19 10:36:20 得分 0

天啦,没有人来看看吗,

!!

继续在线等!!Top

xjbx()回复于 2002-09-19 11:06:14 得分 30

可以调用呀!如果你用frontpage来做asp文件!在“插入”菜单里面有添加“active   x”的选项,把你要添加的“ocx”控件添加进去就可以了,不过该控件要注册!Top

BrightEye(男儿当自强,靠别人不如靠自己)回复于 2002-09-19 11:12:51 得分 40

只要符合控件规范就可以调用,如果是COM控件也可以调用.调用控件一般有良种方法:
1.set   myocx=server.createobject(控件名.类名)
2.利用<object></object>标记Top

zqrhero(zqrhero)回复于 2002-09-19 11:36:08 得分 10

<object   classid=”clsid:20DD1B9E-87C4-11D1-8BE3-0000F8754DA1″   height=20   id=dtBegin   style=”left:   100px;   top:   15px”
width=120   class=”selector”   codebase=”../resource/MSCOMCT2.OCX”>
</object>Top

kaney00(kaney00)回复于 2002-09-19 11:41:44 得分 0

继续问,OCX主要是实现什么东西,??

多谢!!Top

BainStudio(胖胖狗)回复于 2002-09-19 17:45:41 得分 0

关注
Top

xjbx()回复于 2002-09-19 18:04:16 得分 0

OCX主要是实现什么东西?

呵呵,这个问题有点让我无从解释了!:)Top

pyyxs(大力神)回复于 2002-09-19 18:55:27 得分 10

同意   :   BrightEye(问个不休)Top

相关问题

谁有asp调用activex函数的代码 Web 开发 / ASP – CSDN社区 community.csdn.net
http://topic.csdn.net/t/20020729/12/907605.html

谁有asp调用activex函数的代码

lsys(游戏人生)2002-07-29 12:06:04 在 Web 开发 / ASP 提问

delhpi的函数代码
function   TFingerPrint.ReLoading(const   PoliceManCode,   PassWd:   WideString;
FingerCharOne,   FingerCharTwo:   PChar):   Smallint;
begin
。。。
end;
delhpi的函数代码
过程
procedure   TFingerPrint.ImportFingerChar(out   FingerChar:   PChar;
out   FingerID:   Smallint);
begin

end;
求教asp如何的调用

问题点数:100、回复次数:8Top

lanying(蓝鹰)(问个不休)回复于 2002-07-29 13:38:29 得分 10

可以写一个com,用asp调用呀
Top

lsys(游戏人生)回复于 2002-07-29 14:23:44 得分 0

我要源码Top

lsys(游戏人生)回复于 2002-08-01 09:17:54 得分 0

上面的问题没有人回答
改问
asp中如何接收activex中onclick的事件Top

yonghengdizhen(等季节一过,繁花就凋落)回复于 2002-08-01 09:28:56 得分 0

asp中不能接收任何COM对象的事件.

ASP可以处理的只有Application和Session对象的四个事件..

而且ASP中不支持GUI界面的COM对象..

如果说有的话,那不是ASP服务端脚本处理的了,那是客户端浏览器的编程了.Top

yonghengdizhen(等季节一过,繁花就凋落)回复于 2002-08-01 09:31:06 得分 40

asp中不能接收任何COM对象的事件.
这个应该纠正一下,   任何COM对象是指外部COM对象.Top

ramboo2002(天涯游子)回复于 2002-08-01 10:44:13 得分 10

我也想问一下:ASP中如何接收activex中onclick的事件?请高手指教……!
Top

Czh_cz(风清云淡)回复于 2002-08-01 11:06:49 得分 40

应该不可以。
要asp接受activex的返回值,可以给你的activex添加属性,然后给它赋值。
asp   中的脚本可以调用该属性。Top

lsys(游戏人生)回复于 2002-08-03 20:54:37 得分 0

还有没有人有高见,我要结贴了Top

相关问题

ASP中是不是不能调用带有界面的ocx控件? Web 开发 / ASP – CSDN社区 community.csdn.net
http://topic.csdn.net/t/20060303/15/4591007.html

ASP中是不是不能调用带有界面的ocx控件?

devonzzb(水瓶座阿斌)2006-03-03 15:41:20 在 Web 开发 / ASP 提问

现有一个带界面的用于处理图片的ocx控件,嵌入客户端的html页面中使用没有问题。现在我想在服务器端处理用户上传的图片,代码如下:
<OBJECT   name=”oImg”   ID=”oImg”   CLASSID=”CLSID:4475B53F-71F8-403E-9BB8-030685E74834″   runat=”server”></OBJECT>
<%
response.write   TypeName(oImg)   &   “<br>”
const   MAX_SMALL_WIDTH   =   180
const   MAX_MID_WIDTH   =   400

‘########   1   ########
oImg.SetImageTemp(   “C:\”   )                     ”   设置处理图片时所需的临时文件夹
‘########   2   ########
oImg.DrawImage(   “c:\pic\test.jpg”   )   ”   读取图片并显示
%>
现在的问题是,每次执行到1的时候就报错:

错误   ’8000ffff’
灾难性故障

注释掉1,就在2处提示“灾难性故障”

所以,现在怀疑是不是由于这个ocx带界面的缘故?

谢谢关注。 问题点数:100、回复次数:2Top

eglic(圪圪) (理由永远是谎言,信仰永远是自慰)回复于 2006-03-03 15:55:23 得分 100

是的Top

lishery(→SuperBigHero)回复于 2006-03-17 15:57:34 得分 0

这就是传说中的刷分?Top

相关问题

regsvr32.exe使用详解_regsvr32反注册使用方法_CodeLife的WebZine
http://hi.baidu.com/appleluree/blog/item/8bdabbdef505635795ee377d.html
查看文章
regsvr32.exe使用详解_regsvr32反注册使用方法
2007-12-13 13:28
From:烮钬の心

regsvr32.exe是32位系统下使用的DLL注册和反注册工具,使用它必须通过命令行的方式使用,格式是:regsvr32 [/u] [/s] [/n] [/i[:cmdline]] DLL文件名

命令可以在“开始→运行”的文本框中,也可以事先在bat批处理文档中编写好命令。未带任何参数是注册DLL文件功能,其它参数对应功能如下:

/u:反注册DLL文件;

/s:安静模式(Silent)执行命令,即在成功注册/反注册DLL文件前提下不显示结果提示框。

/c:控制端口;

/i:在使用/u反注册时调用DllInstall;

/n:不调用DllRegisterServer,必须与/i连用。

单独运行regsvr32.exe程序,可以看到弹出一“No DLL name specified”的错误提示框,并且可以看到参数原英文提示信息

输入DLL文件名时,如果待处理的是非系统文件,必须在文件名前添加文件绝对路径,必须注意的是文件路径不包含中文,否则很可能导致处理失败。如果碰到regsvr32不能正常执行时,很可能系统文件遭到破坏,因为使用regsvr32.exe 时会调用到Kernel32.dll、User32.dll和Ole32.dll三个文件,在DOS模式或其它系统替换正常文件即可解决。

C#调用第三方ocx控件_DSSH117–毛毛的家园
http://hi.baidu.com/dssh/blog/item/25a56d6070d27944eaf8f800.html
C#调用第三方ocx控件
2007-03-11 12:27

1、.net环境在工具箱上点右键,选择自定义工具箱,然后选择你需要的COM或者OCX控件就可以了。

2、在自定义工具箱中加入相应的控件,设置id,在客户端脚本中直接引用它的ID应可以了,ocx不能作为服务器端使用。

3、不能在asp.net服务端调用ocx, 只能是调用标准的com组件;给你的ocx做一个证书, 捆绑成.cab文件,

然后网页中做 object codebase=”./a.cba” ..

4、http://www.oia.com.cn/Web/CSDN/asppost6/web28039.htm

5、我要开发一个ASP.NET的应用程序,开发工具VS.NET 2003。
在应用程序中要使用公司以前开发的COM组件(可视组件),经试验后发现,COM组件能够被加载到工具箱中,从工具箱能够拖到页面上,不幸的是被作为一个对象插入到.aspx中,没有引入到.aspx.cs中。
例如:
<%@    Page    language=”C#”    Codebehind=”WebForm1.aspx.cs”    AutoEventWireup=”false”    Inherits=”WebTestTTF16.WebForm1″    %>
<!DOCTYPE    HTML    PUBLIC    “-//W3C//DTD    HTML    4.0    Transitional//EN”    >
<HTML>
<HEAD>
<title>WebForm1</title>
<meta    content=”Microsoft    Visual    Studio    .NET    7.1″    name=”GENERATOR”>
<meta    content=”C#”    name=”CODE_LANGUAGE”>
<meta    content=”JavaScript”    name=”vs_defaultClientScript”>
<meta    content=”http://schemas.microsoft.com/intellisense/ie5“    name=”vs_targetSchema”>
</HEAD>
<body    MS_POSITIONING=”GridLayout”>
<form    id=”Form1″    method=”post”    runat=”server”>
<FONT    face=”宋体”>
<OBJECT    style=”Z-INDEX:    104;    LEFT:    24px;    POSITION:    absolute;    TOP:    24px”    classid=”clsid:8E27C92B-1264-101C-8A2F-040224009C02″    VIEWASTEXT>
<PARAM    NAME=”_Version”    VALUE=”524288″>
<PARAM    NAME=”_ExtentX”    VALUE=”7620″>
<PARAM    NAME=”_ExtentY”    VALUE=”5080″>
<PARAM    NAME=”_StockProps”    VALUE=”1″>
<PARAM    NAME=”BackColor”    VALUE=”-2147483633″>
<PARAM    NAME=”Year”    VALUE=”2003″>
<PARAM    NAME=”Month”    VALUE=”10″>
<PARAM    NAME=”Day”    VALUE=”29″>
<PARAM    NAME=”DayLength”    VALUE=”1″>
<PARAM    NAME=”MonthLength”    VALUE=”1″>
<PARAM    NAME=”DayFontColor”    VALUE=”0″>
<PARAM    NAME=”FirstDay”    VALUE=”7″>
<PARAM    NAME=”GridCellEffect”    VALUE=”1″>
<PARAM    NAME=”GridFontColor”    VALUE=”10485760″>
<PARAM    NAME=”GridLinesColor”    VALUE=”-2147483632″>
<PARAM    NAME=”ShowDateSelectors”    VALUE=”-1″>
<PARAM    NAME=”ShowDays”    VALUE=”-1″>
<PARAM    NAME=”ShowHorizontalGrid”    VALUE=”-1″>
<PARAM    NAME=”ShowTitle”    VALUE=”-1″>
<PARAM    NAME=”ShowVerticalGrid”    VALUE=”-1″>
<PARAM    NAME=”TitleFontColor”    VALUE=”10485760″>
<PARAM    NAME=”ValueIsNull”    VALUE=”0″>
</OBJECT>
</FONT>
</form>
</body>
</HTML>
用这种方式,在页面上能够看到这个控件,但使用这种方法我不和道如何在aspx.cs文件中去得到它,控制它?
如果我不用从工具箱拖动控件到页面,我在aspx.cs文件中去创建这个控件,在程序中也能正确使用这个控件,但在页面上是看不到控件的。

我想请大虾指点一下,我如何在页面中能看到这个控件,在asp.cs中又能得到它,就象使用其他控件一样使用它?

回答:

1、把这个控件用命令转换成dll文件,然后引入就OK了。
1、使用TlbImp.exe生成控件.dll的.net引用控件TOBJECTLib.dll。
2、将控件TOBJECTLib.dll引用到你的工程中。
然后就可以象在ASP中一样使用。

2、在ASP。NET中使用OCX一般分以下几个步骤:
一.对生成的DLL文件进行注册
在CMD 中 regsvr32 存放DLL文件地址
二.然后在项目中对DLL进行引用,具体的不详细说明。
三.引用之后在控件栏中你将会看到你刚才添加的控件,直接拖到页面上。
四.就是调用控件中的属性、方法、函数。

C#开发Delphi调用的OCX组件

在类型中添加两个方法,就可以避免注册成为component。

[ComRegisterFunction()]

public static void RegisterClass(string key)

{

StringBuilder sb = new StringBuilder(key);

sb.Replace(@”HKEY_CLASSES_ROOT\”, “”);

RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

RegistryKey ctrl = k.CreateSubKey(“Control”);

ctrl.Close();

RegistryKey inprocServer32 = k.OpenSubKey(“InprocServer32″, true);

inprocServer32.SetValue(“CodeBase”, Assembly.GetExecutingAssembly().CodeBase);

inprocServer32.Close();

k.Close();

}

[ComUnregisterFunction()]

public static void UnregisterClass(string key)

{

StringBuilder sb = new StringBuilder(key);

sb.Replace(@”HKEY_CLASSES_ROOT\”, “”);

RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);

k.DeleteSubKey(“Control”, false);

RegistryKey inprocServer32 = k.OpenSubKey(“InprocServer32″, true);

k.DeleteSubKey(“CodeBase”, false);

k.Close();

}

在.Net 中枚举COM对象的方法和属性名称 – .NET专区 – 新云网络
http://www.newasp.net/tech/net/12490.html

在.Net 中枚举COM对象的方法和属性名称

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2005-6-15 8:32:30
在.Net 中枚举COM对象的方法和属性名称

Author:Zee

恩,以前满世界问过这个问题,没有人理偶的说,还是自己动手搞定比较好。

一般来说,一个COM对象在提供的时候,通常还会提供一个类型库,在其中定义了COM对象的所有方法名称、参数名称、属性名称等等信息。我们要做的就是从类型库中取出这些信息。
当然,某些只供C++程序员使用的COM对象没有类型库,而代之以C++的头文件和/或idl文件,对这种情况,一般没有办法在程序中枚举出对象的方法属性:毕竟去找C++头文件不太现实,何况在非开发环境下,根本就没有头文件的说。
因此,我们将讨论当COM对象存在TypeLib的情况下,枚举方法/属性名称的问题。
从COM对象定位到TypeLib
在一般情况下,COM对象的TypeLib信息存储在注册表中:在HK_CLASSROOT\CLSID\{ClassID}\的注册表项下,有一个名为TypeLib的子项,其中定义了这个COM对象类型库的ID;而在HK_CLASSROOT\TypeLib 注册表项下,列举了系统中所有TypeLib。
看看我们首先要做什么:从ProgID 取得 ClassID,这个工作可以通过调用COM 基础库的 CLSIDFromProgID 函数来完成,在Platform SDK中,该函数的定义如下:

HRESULT CLSIDFromProgID(
  LPCOLESTR lpszProgID,
  LPCLSID pclsid

);

为了在.Net中使用这个函数,我们用DllImport Attribute 把这个函数引入.Net 中:

class UnsafeNativeMethods{
[DllImport("ole32.dll",CharSet=CharSet.Unicode,PreserveSig=false)]
public static extern void CLSIDFromProgID([In,MarshalAs(UnmanagedType.BStr)] string lpszProgID,[Out]out Guid pclsid);
………

然后,我们可以在.Net 中调用这个函数取得ClassID了:

Guid clsid;
UnsafeNativeMethods.CLSIDFromProgID(progID,out clsid);

OK, 升级宝物Class ID 入手,Level Up!Strength + 3, Life + 5,必杀技 dll import 习得。 :) 下一个任务:取得TypeLib。
l         取得TypeLib。
为访问TypeLib,COM 提供了二个接口:ITypeLib 和 ITypeInfo,其中ITypeLib 提供对 TypeLib 的访问,而ITypeInfo 则表示TypeLib中定义的某一项ITypeInfo。
要获得ITypeInfo,COM有二个函数可以做这件事情:LoadTypeLib 和 LoadRegTypeLib。其中 LoadTypeLib 需要 TypeLib 文件的路径作为参数,而LoadRegTypeLib 则根据TypeLib的TypeLib ID和TypeLib的版本号取得 ITypeLib。在这里,我们用LoadRegTypeLib来取得ITypeLib 接口。
先来准备需要的参数:TypeLibID和TypeLib的版本号,这些信息需要从注册表里得到:

RegistryKey regKey = Registry.ClassesRoot;
regKey = regKey.OpenSubKey(“CLSID\\{” + clsid.ToString() + “}\\TypeLib”);
Guid typeLibID = new Guid(regKey.GetValue(“”).ToString());
//Get TypeLib Versions
short iMajorVer,iMinusVer;
regKey = Microsoft.Win32.Registry.ClassesRoot;
regKey = regKey.OpenSubKey(“TypeLib\\{” + typeLibID.ToString() + “}”);
string[] aryTemp = regKey.GetSubKeyNames();
string sVersion = aryTemp[0];
aryTemp = sVersion.Split(‘.’);
iMajorVer = short.Parse(aryTemp[0],System.Globalization.NumberStyles.AllowHexSpecifier);
iMinusVer = short.Parse(aryTemp[1] ,System.Globalization.NumberStyles.AllowHexSpecifier);

这里要注意一点:在注册表里记录的TypeLib版本号是以十六进制格式表示的,运气好的话,你会发现类似”1.a”之类的版本号,所以我们最好把它们看成16进制来转换。
现在可以调用LoadRegTypeLib 了,和CLSIDFromProgID一样,先import进来:
这是LoadRegTypeLib 的函数原型:

HRESULT LoadRegTypeLib( 
  REFGUID  rguid,             
  unsigned short  wVerMajor,  
  unsigned short  wVerMinor,  
  LCID  lcid,                 
  ITypeLib FAR* FAR*  pptlib  

);

恩,在.Net里,这个函数是这个样子的:

[DllImport("oleaut32.dll",CharSet=CharSet.Unicode,PreserveSig=false)]
[LCIDConversion(3)]
public static extern UCOMITypeLib LoadRegTypeLib(ref Guid rguid, [In,MarshalAs(UnmanagedType.U2)]short wVerMajor, [In,MarshalAs(UnmanagedType.U2)]short wVerMinor);

哈,一个小小的技巧:在.Net 的定义里,偶没有定义原型里 lcid 这个参数,这是因为偶应用了LCIDConversionAttribute,这个Attribute 意思就是说这个方法需要一个LCID做参数,参数的位置嘛:[LCIDConversion(3)]——第三个参数。这样在调用这个方法的时候,.Net 的封送拆收器将自动提供 LCID 参数。不错把:)
另外,在.Net Framwork的System.Runtime.InteropServices 命名空间里,定义了一些常用COM Interface的.Net托管定义,虽然不多,但幸运的是我们要用到的ITypeLib和 ITypeInfo这二个接口都有,也就是System.Runtime.InteropService.UCOMITypeLibSystem.Runtime.InteropService.UCOMITypeInfo。这就省下了我们自己定义接口的工作。
好了,接下来的事情狠简单了:

UCOMITypeLib typeLib;
typeLib = UnsafeNativeMethods.LoadRegTypeLib(ref typeLibID,iMajorVer,iMinusVer);

Bingo!Mission Complete!只剩下最后一个任务:定位到对应我们的COM对象的ITypeInfo,并从中取出我们需要的信息。
ITypeInfo接口的GetITypeInfo方法和GetITypeInfoCount方法一起提供了遍历TypeLib中所有ITypeInfo的能力,不过既然我们手上有COM对象的ClassID,利用GetITypeInfoOfGuid 方法就可以获得COM对象的ITypeInfo了。

UCOMITypeInfo ITypeInfo;
typeLib.GetITypeInfoOfGuid(ref clsid,out ITypeInfo);

拿到ITypeInfo之后,首先我们需要看看这个ITypeInfo里有多少方法/属性,这需要我们调用它的GetTypeAttr 方法获得TYPEATTR结构。

TYPEATTR typeattr;
IntPtr p_typeattr = IntPtr.Zero;
ITypeInfo.GetTypeAttr(out p_typeattr);
typeattr = (TYPEATTR)Marshal.PtrToStructure(p_typeattr,typeof(TYPEATTR));

获得TYPEATTR结构有那么一点点麻烦,因为 .Net的不支持非托管签名的 TYPEATTR** 参数,所以只有使用引用 IntPtr 参数定义 GetTypeAttr。然后我们需要用Marshal.PtrToStructure将数据从非托管内存块封送到托管对象。在TYPEATTR结构中,cFuns字段表示当前TrpeInfo描述的函数数目,而每个函数的描述则是通过ITypeInfo的GetFuncDesc方法取得的FUNCDESC结构描述的。

if(typeattr.cFuncs > 0)
{
for(int i=0;i<typeattr.cFuncs;++i)
{
//Get FUNCDESC struct
FUNCDESC funcdesc;
IntPtr p_funcDesc;
ITypeInfo.GetFuncDesc(i,out p_funcDesc);
funcdesc = (FUNCDESC)Marshal.PtrToStructure(p_funcDesc,typeof(FUNCDESC));
……

和TYPEATTR一样,FUNCDESC结构也需要Marshal.PtrToStructure处理一下,偶就不多说了。
讨厌的是:FUNCDESC结构里并没有函数的名称,我们只能通过它的memid字段和invkind字段知道这个函数的成员ID和函数的类型。函数的类型是我们需要的:它告诉我们这个函数是一个方法或者是一个属性的Get/Set方法,而名称这个东西,我们还得求助于ITypeInfo:GetNames 方法获取具有指定成员ID的成员名称,它的返回一个string数组,对方法而言,这个数组第一个元素是方法名称,后面的元素则是方法的参数名,而对属性而言,属性名称也出现在数组的第一个元素。
好了,现在除了一件事情,该说的偶已经都说了,我们已经知道了如何从ITypeInfo获得方法/属性的名称,至于如何如何先建立二个空的Collection分别用于存放方法和属性名称;如何如何遍历ITypeInfo的所有FuncDesc,根据每个不同的函数类型向对应的Collection中插入元素,这些简单操作偶就不想多说了。我们剩下的唯一的问题是:对所有VB生成的COM对象,按照上面的步骤走下来,我们什么方法属性也看不到。
原因嘛,用OleView看一下这些dll的TypeLib就明白了:VB会生成一个名为”_”+类名的类接口,这个接口继承自IDispatch,所有的方法属性都在这个接口上定义,而实现类只是简单的实现这个接口,在它的TypeLib里,真正对应ClassID的实现类里没有任何成员。
既然知道了原因,办法也就有了:我们在枚举一个COM对象的所有方法/属性时,不应该只枚举仅对应它自己ClassID的TypeInfo,这个TypeInfo继承的所有其他接口中定义的方法/属性也要照样拿出来,而要定位到它继承的其他接口,我们要做的事情其实和遍历这个ITypeInfo的所有FUNCDESC差不多:

if(typeattr.cImplTypes > 0)
{
for(int i=0;i<typeattr.cImplTypes;++i)
{
int href;
UCOMITypeInfo imptypeinfo;
typeinfo.GetRefTypeOfImplType(i,out href);
typeinfo.GetRefTypeInfo(href,out imptypeinfo);
//Now we can do the same thing to the imptypeinfo like typeinfo
……
}
}

TYPEATTR的cImplTypes字段表示这个ItypeInfo实现的接口数目,ITypeInfo的GetRefTypeOfImplType 方法获取对某个已实现接口的句柄的引用,而GetRefTypeInfo 方法从这个句柄的引用获取该接口的ITypeInfo。很明显,我们可以写一个递归函数来走遍所有COM对象实现的接口,而且我们可以确信这个递归是有出口的:因为COM里所有的接口归根到底都派生自“我不知道”接口 。^-^
最后,我想在大多数情况下,你不会希望在COM对象的方法列表里看到QueryInterface或者AddRef这类IUnknown接口的方法,而IDispatch接口那些类似Invoke之类的方法想来有兴趣的人也不多,不过反正这种底层方法就那么几个,在你遍历的时候尽可以判断一下过滤掉这些方法名称。

免责声明:
在本文中,为了清晰起见,所有给出的代码中都没有错误处理。如果你在你的代码中使用本文中的部分代码,由此造成的诸如程序出错、系统宕机、走路撞树、手机爆炸、洪水毁堤、地球毁灭等等一切后果,本人概不负责

CodeProject: Calling Managed .NET C# COM Objects from Unmanaged C++ Code. Free source code and
http://www.codeproject.com/KB/cs/ManagedCOM.aspx

Preface

COM Interoperability is the feature of Microsoft .NET that allows managed .NET code to interact with unmanaged code using Microsoft’s Component Object Model semantics.

This article is geared towards C# programmers who are familiar with developing COM components and familiar with the concept of an interface. I’ll review some background on COM, explain how C# interacts with COM, and then show how to design .NET components to smoothly interact with COM.

For those die-hard COM experts, there will be some things in this article that are oversimplified, but the concepts, as presented, are the important points to know for those developers supplementing their COM code with .NET components.

Introduction

.NET Interfaces and Classes

The basis for accessing .NET objects either from other .NET code or from unmanaged code is the Class. A .NET class represents the encapsulation of the functionality (methods and properties) that the programmer wants to expose to other code. A .NET interface is the abstract declaration of the methods and properties that classes which implement the interface are expected to provide in their implementations. Declaring a .NET interface doesn’t generate any code, and a .NET interface is not callable directly. But any class which implements (“inherits”) the interface must provide the code that implements each of the methods and properties declared in the interface definition.

Microsoft realized that the very first version of .NET needed a way to work with the existing Windows technology used to develop applications over the past 8+ years: COM. With that in mind, Microsoft added support in the .NET runtime for interoperating with COM – simply called “COM Interop”. The support goes both ways: .NET code can call COM components, and COM code can call .NET components.

Using the code

Steps to create a Managed .NET C# COM Object:

  1. Open VS.NET2003->New Project->Visual C# Projects->Class Library.
  2. Project name: MyInterop.
  3. Create MyDoNetClass.cs file, and add the following lines of code:
    Collapse
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
  4. Create an Interface IMyDotNetInterface.
  5. Create a class MyDoNetClass.
  6. Add the following line for MyDotNetClass:
    Collapse
    [ClassInterface(ClassInterfaceType.None)]

Although a .NET class is not directly invokable from unmanaged code, Microsoft has provided the capability of wrapping a .NET interface in an unmanaged layer of code that exposes the methods and properties of the .NET class as if the class were a COM object. There are two requirements for making a .NET class visible to unmanaged code as a COM object:

Requirement 1:

You have to add GUIDs – Globally Unique Identifiers – into your code for the interface and the class separately, through a GUID tool.

  1. Now, create a GUID for the Interface, and add the following line for the interface:
    Collapse
    [Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
  2. Now, create a GUID for the class, and add the following line for the class:
    Collapse
    [Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
  3. Your code will look like:
    Collapse
    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace MyInterop
    {
        [Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
        interface IMyDotNetInterface
        {
            void ShowCOMDialog();
        }
    
        [ClassInterface(ClassInterfaceType.None)]
        [Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
        class MyDotNetClass : IMyDotNetInterface
        {
            // Need a public default constructor for COM Interop.
    
            public MyDotNetClass()
            {}
            public void ShowCOMDialog()
            {
                System.Windows.Forms.MessageBox.Show(“I am a" +
                      "  Managed DotNET C# COM Object Dialog”);
            }
        }
    }
  4. Compile the solution.
  5. You will see inside the project directory->obj->debug directory, the file “MyInterop.dll” generated after compilation.

Requirement 2:

Registration of the COM Class and Interfaces

For a COM class to be accessible by the client at runtime, the COM infrastructure must know how to locate the code that implements the COM class. COM doesn’t know about .NET classes, but .NET provides a general “surrogate” DLL – mscoree.dll — which acts as the wrapper and intermediary between the COM client and the .NET class.

  1. Hard-code a specific version number in your AssemblyVersion attribute in the AssemblyInfo.cs file which is in your project.Example:
    Collapse
    [assembly: AssemblyVersion("1.0.0.0")]
  2. Create a strong-name key pair for your assembly and point to it via the AssemblyKeyFile attribute in the AssemblyInfo.cs file which is in your project. Example:
    Collapse
    sn -k TestKeyPair.snk
    Collapse
    [assembly: AssemblyKeyFile("TestKeyPair.snk")]
  3. Add your assembly to the GAC using the following command:
    Collapse
    gacutil /i MyInterop.dll
  4. Register your assembly for COM by using the REGASM command along with the “/tlb” option to generate a COM type library.
    Collapse
    REGASM MyInterop.dll /tlb:com.MyInterop.tlb
  5. Close the C# project.

Steps to create an Unmanaged C++ application to call a .NET Managed C# COM

  1. Open VS.NET2003->New Project->Visual C++ Projects->Win32->Win32 Console Project.
  2. Name: DotNet_COM_Call.
  3. Include the following line in your DoNet_COM_Call.cpp file:
    Collapse
    #import<Full Path>\com.MyInterop.tlb" named_guids raw_interfaces_only
  4. Compile the solution.
  5. It will generate a “com.myinterop.tlh” file into your project->debug directory.
  6. You can open this file and see the contents. This is basically the proxy code of the C# COM code.
  7. Now, you can write the code to call the .NET Managed COM.
  8. Please add the following lines of code before calling the COM exported functions:
    Collapse
    CoInitialize(NULL);   //Initialize all COM Components
    
    
    // <namespace>::<InterfaceName>
    
    MyInterop::IMyDotNetInterfacePtr pDotNetCOMPtr;
    
    // CreateInstance parameters
    
    // e.g. CreateInstance (<namespace::CLSID_<ClassName>)
    
    HRESULT hRes =
      pDotNetCOMPtr.CreateInstance(MyInterop::CLSID_MyDotNetClass);
    if (hRes == S_OK)
    {
        BSTR str;
        pDotNetCOMPtr->ShowCOMDialog ();
        //call .NET COM exported function ShowDialog ()
    
    }
    
    CoUninitialize ();   //DeInitialize all COM Components
  9. Run this console application.
  10. Expected result: a managed code (C# ) dialog should appear with the string “I am a Managed DotNET C# COM Object Dialog”.

Points of Interest

While creating an Interface for COM exported functions, creating GUIDs for the Interface and the class and registering the class are required steps, and doing all this is always interesting and fun. Calling parameterized exported functions also is very interesting.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Atul Mani Atul Mani Tripathi has been a professional developer since 1997 and working as a senior consultant with Cognizant Technology Solutions (CTS) .

Most of the time, his focus is on creating a clean and simple solution to development problems. He is a C++, Visual C++ and C# (Dot NET) guy who loves Visual Studio, Google, Code Project and developing personal projects.

Occupation: Web Developer
Location: United States United States

Other popular C# articles:

请问.odl和.idl有什么区别啊? VC/MFC / ATL/ActiveX/COM – CSDN社区 community.csdn.net
http://topic.csdn.net/t/20040427/17/3014084.html

请问.odl和.idl有什么区别啊?

cctime()2004-04-27 17:25:36 在 VC/MFC / ATL/ActiveX/COM 提问

as   title 问题点数:0、回复次数:5Top

Onega(www.fruitfruit.com回复于 2004-04-27 17:48:32 得分 0

When   using   IDL,   you   must   declare   the   interfaces   that   will   generate   the   C++   source   files   outside   of   the   library   declaration.   For   the   ODL,   this   step   is   not   necessary.   Other   than   a   few   minor   language   differences,   the   IDL   and   ODL   are   identical   in   terms   of   syntax   and   organization.
Top

yaoyuhang(tom)回复于 2004-04-27 21:14:33 得分 0

.odl和.idl在com中的功能相同.
前者是ActiveX中的   后者是ATL中.

可在前者的文件中   用   #import   “XXXXX.idl”   的方式包含后者.   反过来没有试过.

Top

ygang76(小草)回复于 2004-04-27 22:15:27 得分 0

ODL是Microsoft对IDL的扩展Top

ddkc_c(ddkc_c)回复于 2004-04-28 08:47:19 得分 0

odl已经过时了,现在是idl的天下
现在使用idl就行了Top

wangweixing2000(星(inspiration(灵感)))回复于 2004-04-28 09:18:08 得分 0

odl   —对象描述语言
idl   —接口描述语言
其实是一个功能就是在写法上有些不同,eg:
odl:
[
uuid(3C591B20-1F13-101B-B826-00DD01103DE1),             //   LIBID_Lines.
helpstring("Lines   1.0   Type   Library"),
lcid(0x09),
version(1.0)
]
library   Lines
{
importlib(“stdole.tlb”);

[
uuid(3C591B25-1F13-101B-B826-00DD01103DE1),     //   IID_Ipoint.
helpstring("Point   object."),
oleautomation,
dual
]
interface   IPoint   :   IDispatch
{
[propget,   helpstring("Returns   and   sets   x   coordinate.")]
HRESULT   x([out,   retval]   int*   retval);
[propput,   helpstring("Returns   and   sets   x   coordinate.")]
HRESULT   x([in]   int   Value);

[propget,   helpstring("Returns   and   sets   y   coordinate.")]
HRESULT   y([out,   retval]   int*   retval);
[propput,   helpstring("Returns   and   sets   y   coordinate.")]
HRESULT   y([in]   int   Value);
}
[
uuid(3C591B21-1F13-101B-B826-00DD01103DE1),       //   CLSID_Lines.
helpstring("Lines   Class"),
appobject
]
coclass   Lines
{
[default]   interface   IPoint;
interface   IDispatch;
}
}
idl:

[
uuid(3C591B25-1F13-101B-B826-00DD01103DE1),     //   IID_Ipoint.
helpstring("Point   object."),
oleautomation,
dual
]
interface   IPoint   :   IDispatch
{
[propget,   helpstring("Returns   and   sets   x   coordinate.")]
HRESULT   x([out,   retval]   int*   retval);
[propput,   helpstring("Returns   and   sets   x   coordinate.")]
HRESULT   x([in]   int   Value);

[propget,   helpstring("Returns   and   sets   y   coordinate.")]
HRESULT   y([out,   retval]   int*   retval);
[propput,   helpstring("Returns   and   sets   y   coordinate.")]
HRESULT   y([in]   int   Value);
}
[
uuid(3C591B20-1F13-101B-B826-00DD01103DE1),             //   LIBID_Lines.
helpstring("Lines   1.0   Type   Library"),
lcid(0x09),
version(1.0)
]
library   Lines
{
importlib(“stdole32.tlb”);
importlib(“stdole2.tlb”);

[
uuid(3C591B21-1F13-101B-B826-00DD01103DE1),       //   CLSID_Lines.
helpstring("Lines   Class"),
appobject
]
coclass   Lines
{
[default]   interface   IPoint;
interface   IDispatch;
}
}Top

相关问题

WideCharToMultiByte
2008年08月19日 星期二 11:42
仔细做好串处理
这一部分将花点时间来讨论如何在COM代码中处理串。如果你熟悉Unicode 和ANSI,并知道如何对它们进行转换的话,你就可以跳过这一部分,否则还是读一下这一部分的内容。
不管什么时候,只要COM方法返回一个串,这个串都是Unicode串(这里指的是写入COM规范的所有方法)。Unicode是一种字符编码集,类似ASCII,但用两个字节表示一个字符。如果你想更好地控制或操作串的话,应该将它转换成TCHAR类型串。
TCHAR和以_t开头的函数(如_tcscpy())被设计用来让你用相同的源代码处理Unicode和ANSI串。在大多数情况下编写的代码都是用来处理ANSI串和ANSI WindowsAPIs,所以在下文中,除非另外说明,我所说的字符/串都是指TCHAR类型。你应该熟练掌握TCHAR类型,尤其是当你阅读其他人写的有关代码时,要特别注意TCHAR类型。
当你从某个COM方法返回得到一个Unicode串时,可以用下列几种方法之一将它转换成char类型串:

1、调用 WideCharToMultiByte() API。
2、调用CRT 函数wcstombs()。
3、使用CString 构造器或赋值操作(仅用于MFC )。
4、使用ATL 串转换宏。

WideCharToMultiByte()
你可以用WideCharToMultiByte()将一个Unicode串转换成一个ANSI串。此函数的原型如下:
int WideCharToMultiByte (
    UINT    CodePage,
    DWORD   dwFlags,
    LPCWSTR lpWideCharStr,
    int     cchWideChar,
    LPSTR   lpMultiByteStr,
    int     cbMultiByte,
    LPCSTR  lpDefaultChar,
    LPBOOL  lpUsedDefaultChar );
以下是参数解释:
CodePage
Unicode字符转换成的代码页。你可以传递CP_ACP来使用当前的ANSI代码页。代码页是256个字符集。字符0——127与ANSI编码一样。字符128——255与ANSI字符不同,它可以包含图形字符或者读音符号。每一种语言或地区都有其自己的代码页,所以使用正确的代码页对于正确地显示重音字符很重要。
dwFlags
dwFlags 确定Windows如何处理“复合” Unicode字符,它是一种后面带读音符号的字符。如è就是一个复合字符。如果这些字符在CodePage参数指定的代码页中,不会出什么事。否则,Windows必须对之进行转换。
传递WC_COMPOSITECHECK使得这个API检查非映射复合字符。
传递WC_SEPCHARS使得Windows将字符分为两段,即字符加读音,如e`。
传递WC_DISCARDNS使得Windows丢弃读音符号。
传递WC_DEFAULTCHAR使得Windows用lpDefaultChar参数中说明的缺省字符替代复合字符。
缺省行为是WC_SEPCHARS。
lpWideCharStr
要转换的Unicode串。
cchWideChar
lpWideCharStr在Unicode 字符中的长度。通常传递-1,表示这个串是以0×00结尾。
lpMultiByteStr
接受转换的串的字符缓冲
cbMultiByte
lpMultiByteStr的字节大小。
lpDefaultChar
可选——当dwFlags包含WC_COMPOSITECHECK | WC_DEFAULTCHAR并且某个Unicode字符不能被映射到同等的ANSI串时所传递的一个单字符ANSI串,包含被插入的“缺省”字符。可以传递NULL,让API使用系统缺省字符(一种写法是一个问号)。
lpUsedDefaultChar
可选——指向BOOL类型的一个指针,设置它来表示是否缺省字符曾被插入ANSI串。可以传递NULL来忽略这个参数。
我自己都有点晕菜了……!,万事开头难啊……,不搞清楚这些东西就很难搞清楚COM的串处理。何况文档中列出的比实际应用的要复杂得多。下面就给出了如何使用这个API的例子:
// 假设已经有了一个Unicode 串 wszSomeString...
char szANSIString [MAX_PATH];

    WideCharToMultiByte ( CP_ACP,                // ANSI 代码页
                          WC_COMPOSITECHECK, // 检查重音字符
                          wszSomeString,         // 原Unicode 串
                          -1,                    // -1 意思是串以0x00结尾
                          szANSIString,          // 目的char字符串
                          sizeof(szANSIString),  // 缓冲大小
                          NULL,                  // 肥缺省字符串
                          NULL );                // 忽略这个参数
调用这个函数后,szANSIString将包含Unicode串的ANSI版本。
wcstombs()
这个CRT函数wcstombs()是个简化版,但它终结了WideCharToMultiByte()的调用,所以最终结果是一样的。其原型如下:
size_t wcstombs (
    char*          mbstr,
    const wchar_t* wcstr,
    size_t         count );
以下是参数解释:
mbstr
接受结果ANSI串的字符(char)缓冲。
wcstr
要转换的Unicode串。
count
mbstr参数所指的缓冲大小。

wcstombs()在它对WideCharToMultiByte()的调用中使用WC_COMPOSITECHECK | WC_SEPCHARS标志。用wcstombs()转换前面例子中的Unicode串,结果一样:

wcstombs ( szANSIString, wszSomeString, sizeof(szANSIString) );

CString
MFC中的CString包含有构造函数和接受Unicode串的赋值操作,所以你可以用CString来实现转换。例如:

// 假设有一个Unicode串wszSomeString…

CString str1 ( wszSomeString ); // 用构造器转换
CString str2;

str2 = wszSomeString; // 用赋值操作转换

ATL宏
ATL有一组很方便的宏用于串的转换。W2A()用于将Unicode串转换为ANSI串(记忆方法是“wide to ANSI”——宽字符到ANSI)。实际上使用OLE2A()更精确,“OLE”表示的意思是COM串或者OLE串。下面是使用这些宏的例子:

#include <atlconv.h>

// 还是假设有一个Unicode串wszSomeString…

{
char szANSIString [MAX_PATH];
USES_CONVERSION; // 声明这个宏要使用的局部变量

lstrcpy ( szANSIString, OLE2A(wszSomeString) );
}

OLE2A()宏“返回”转换的串的指针,但转换的串被存储在某个临时栈变量中,所以要用lstrcpy()来获得自己的拷贝。其它的几个宏是W2T()(Unicode 到 TCHAR)以及W2CT()(Unicode到常量TCHAR串)。
有个宏是OLE2CA()(Unicode到常量char串),可以被用到上面的例子中,OLE2CA()实际上是个更正宏,因为lstrcpy()的第二个参数是一个常量char*,关于这个问题本文将在以后作详细讨论。
另一方面,如果你不想做以上复杂的串处理,尽管让它还保持为Unicode串,如果编写的是控制台应用程序,输出/显示Unicode串时应该用全程变量std::wcout,如:

wcout << wszSomeString;

但是要记住,std::wcout只认Unicode,所以你要是“正常”串的话,还得用std::cout输出/显示。对于Unicode串文字量,要使用前缀L标示,如:

wcout << L”The Oracle says…” << endl << wszOracleResponse;

如果保持串为Unicode,编程时有两个限制:

—— 必须使用wcsXXX() Unicode串处理函数,如wcslen()。
—— 在Windows 9x环境中不能在Windows API中传递Unicode串。要想编写能在9x和NT上都能运行的应用,必须使用TCHAR类型,详情请参考MSDN。

用例子代码总结上述内容
下面用两个例子演示本文所讲的COM概念。代码中还包含了本文的例子工程。
使用单接口COM对象
第一个例子展示的是单接口COM对象。这可能是你碰到得最简单的例子。它使用外壳中的活动桌面组件对象类(CLSID_ActiveDesktop)来获得当前桌面墙纸的文件名。请确认系统中安装了活动桌面(Active Desktop)。

以下是编程步骤:

初始化COM库。 (Initialize)
创建一个与活动桌面交互的COM对象,并取得IActiveDesktop接口。
调用COM对象的GetWallpaper()方法。
如果GetWallpaper()成功,则输出/显示墙纸文件名。
释放接口(Release())。
收回COM库(Uninitialize)。

WCHAR   wszWallpaper [MAX_PATH];
CString strPath;
HRESULT hr;
IActiveDesktop* pIAD;

    // 1. 初始化COM库(让Windows加载DLLs)。通常是在程序的InitInstance()中调用
    // CoInitialize ( NULL )或其它启动代码。MFC程序使用AfxOleInit()。

    CoInitialize ( NULL );

    // 2. 使用外壳提供的活动桌面组件对象类创建COM对象。
    // 第四个参数通知COM需要什么接口(这里是IActiveDesktop).

    hr = CoCreateInstance ( CLSID_ActiveDesktop,
                            NULL,
                            CLSCTX_INPROC_SERVER,
                            IID_IActiveDesktop,
                            (void**) &pIAD );

    if ( SUCCEEDED(hr) )
        {
        // 3. 如果COM对象被创建成功,则调用这个对象的GetWallpaper() 方法。
        hr = pIAD->GetWallpaper ( wszWallpaper, MAX_PATH, 0 );

        if ( SUCCEEDED(hr) )
            {
            // 4. 如果 GetWallpaper() 成功,则输出它返回的文件名字。
            // 注意这里使用wcout 来显示Unicode 串wszWallpaper.  wcout 是
            // Unicode 专用,功能与cout.相同。
            wcout << L"Wallpaper path is:\n    " << wszWallpaper << endl << endl;
            }
        else
            {
            cout << _T("GetWallpaper() failed.") << endl << endl;
            }

        // 5. 释放接口。
        pIAD->Release();
        }
    else
        {
        cout << _T("CoCreateInstance() failed.") << endl << endl;
        }

    // 6. 收回COM库。MFC 程序不用这一步,它自动完成。
CoUninitialize();
在这个例子中,输出/显示Unicode 串 wszWallpaper用的是std::wcout。
标签: COM字符串

VC知识库文章 – COM 组件设计与应用(四)——简单调用组件
http://www.vckbase.com/document/viewdoc/?id=1493
::首页 >> 文档中心 >> 在线杂志 >> COM技术(COM/DCOM/COM+) [ 在线杂志 第43期 ]
[ 原创文档 本文适合中级读者 已阅读47452次 ] 文档 代码 工具

COM组件设计与应用(四)
简单调用组件

作者:杨老师

一、前言

同志们、朋友们、各位领导,大家好。

VCKBASE 不得了,
网友众多文章好。
组件设计怎么学?
知识库里闷头找!
摘自—杨老师打油集录

VCKBASE 的顶力支持下,在各位网友回帖的鼓励下,我才能顺利完成系列论文的前三回。书到本回,我们终于开始写代码啦。写点啥那?恩,有了!咱们先从如何调用现成的简单的组件开始吧,同时也顺便介绍一些相关的知识。


二、组件的启动和释放

第三回中,大家用“小本本”记录了一个原则:COM 组件是运行在分布式环境中的 。于是,如何启动组件立刻就遇到了严重的问题,大家看这段代码:

      p = new 对象;
      p->对象函数();
      delete p;

这样的代码再熟悉不过了,在本地进程中运行是不会有问题的。但是你想想,如果这个对象是在“地球另一边”的计算机上,结果会如何?嘿嘿,C++ 在设计 new 的时候,可没有考虑远程的实现呀(计算机语言当然不会,也没必要去设计)。因此启动组件、调用接口的功能,当然就由 COM 系统来实现了。


图一 组件调用机制

由上图可以看出,当调用组件的时候,其实是依靠代理(运行在本地)和存根(运行在远端)之间的通讯完成的。具体来说,当客户程序通过 CoCreateInstance() 函数启动组件,则代理接管该调用,它和存根通讯,存根则它所在的本地(相对于客户程序来说就是远程了)执行 new 操作加载对象。对于初学者,你可以不用理它,代理和存根对我们来说是透明的。只要大约知道是怎么一回事就一切OK了。
问题又来了,这个远程的对象什么时候消灭呢?在第二回介绍接口概念的时候,当时我们特意忽略了两个函数,就是IUnknown::AddRef()和IUnknown::Release(),从函数名就能猜到了,一个是对内部引用记数器(Ref)加1,一个是释放(减1),当记数器减为0的时候,就是释放的机会啦。看起来很复杂,没办法,因为这是在介绍原理。其实在我们写程序的时候到比较简单,请大家遵守几个原则:
1、启动组件得到一个接口指针(Interface)后,不要调用AddRef()。因为系统知道你得到了一个指针,所以它已经帮你调用了AddRef()函数;
2、通过QueryInterface()得到另一个接口指针后,不要调用AddRef()。因为……和上面的道理一样;
3、当你把接口指针赋值给(保存到)另一个变量中的时候,请调用AddRef();
4、当不需要再使用接口指针的时候,务必执行Release()释放;
5、当使用智能指针的时候,可以省略指针的维护工作;(注1)


三、内存分配和释放

自从学习了C语言,老师就教导我们说:对于动态内存的申请和释放,一定要遵守“谁申请,谁释放”的原则。在此原则的指导下,不仅是我、不仅是你,就连特级大师都设计了这样怪怪的函数:

函数 说明 评论
GetWindowText(HWND,LPTSTR,int) 取得窗口标题。需要在参数中给出保存标题所使用的内存指针,和这块内存的尺寸。 晕!我又不知道窗口标题的长度,居然还要我提供尺寸?!没办法,只能估摸着给一个大一些的尺寸吧。
sprintf(char *,const char *,…) 格式化一个字符串。这个函数不用给出缓冲区的长度啦。 恩,虽然不用给出长度了,但你敢给个小尺寸吗?哼!
int CListBox::GetTextLen(int)
CListBox::GetText(int,LPTSTR)
取得列表窗中子项目的标题。需要调用两个函数,先取得长度,然后分配内存,再实际取得标题内容。 真烦!

说实在的,不但函数调用者感觉别扭,就连函数设计者心情也不会爽的,而这一切都是为了满足所谓“谁申请,谁释放”的原则。 解决这个问题最好的方式就是:函数内部根据实际需要动态申请内存,而调用者负责释放。这虽然违背了上述原则,但 COM 从方便性和效率出发,确实是这么设计的。

C语言 C++语言 Windows 平台 COM IMalloc 接口 BSTR
申请 malloc() new GlobalAlloc() CoTaskMemAlloc() Alloc() SysAllocString()
重新申请 realloc() GlobalReAlloc() CoTaskRealloc() Realloc() SysReAllocString()
释放 free() delete GlobalFree() CoTaskMemFree() Free() SysFreeString()

以上这些函数必须要按类型配合使用(比如:new 申请的内存,则必须用 delete 释放)。在 COM 内部,当然你可以随便使用任何类型的内存分配释放函数,但组件如果需要与客户进行内存的交互,则必须使用上表中的后三类函数族。
1、BSTR 内存在上回书中,已经有比较丰富的介绍了,不再重复;
2、CoTaskXXX()函数族,其本质上就是调用C语言的函数(malloc…);
3、IMalloc 接口又是对 CoTaskXXX() 函数族的一个包装。包装后,同时增强了一些功能,比如:IMalloc::GetSize()可以取得尺寸,使用 IMallocSpy 可以监视内存的使用;

四、参数传递方向

在C语言的函数声明中,尤其当参数为指针的时候,你是看不出它传递方向的。比如:
void fun(char * p1, int * p2); 请问,p1、p2 哪个是入参?哪个是出参?甚或都是入参或都是出参?由于牵扯到内存分配和释放等问题,COM 需要明确标注参数方向。以后我们写程序,就类似下面的样子:

      HRESULT Add([in] long n1, [in] long n2, [out] long *pnSum);  // IDL文件(注2)
      STDMETHOD(Add)(/*[in]*/ long n1, /*[in]*/ long n2, /*[out]*/ long *pnSum);  // .h文件

如果参数是动态分配的内存指针,那么遵守如下的规定:

方向 申请人 释放人 提示
[in] 调用者 调用者 组件接收指针后,不能重新分配内存
[out] 组件 调用者 组件返回指针后,调用者“爱咋咋地”(注3)
[in,out] 调用者 调用者 组件可以重新分配内存

五、示例程序

示例一、由 CLSID 得到 ProgID。(程序以 word 为例子。如果运行不正确,嘿嘿,你没有安装 word 吧?)

	::CoInitialize( NULL );

	HRESULT hr;
	// {000209FF-0000-0000-C000-000000000046} = word.application.9
	CLSID clsid = {0x209ff,0,0,{0xc0,0,0,0,0,0,0,0x46}};
	LPOLESTR lpwProgID = NULL;

	hr = ::ProgIDFromCLSID( clsid, &lpwProgID );
	if ( SUCCEEDED(hr) )
	{
		::MessageBoxW( NULL, lpwProgID, L"ProgID", MB_OK );

		IMalloc * pMalloc = NULL;
		hr = ::CoGetMalloc( 1, &pMalloc );  // 取得 IMalloc
		if ( SUCCEEDED(hr) )
		{
			pMalloc->Free( lpwProgID );  // 释放ProgID内存
			pMalloc->Release();          // 释放IMalloc
		}
	}

	::CoUninitialize();

示例二、如何使用“浏览文件夹”选择对话窗。

CString BrowseFolder(HWND hWnd, LPCTSTR lpTitle)
{
    // 调用 SHBrowseForFolder 取得目录(文件夹)名称
    // 参数 hWnd: 父窗口句柄
    // 参数 lpTitle: 窗口标题

    char szPath[MAX_PATH]={0};
    BROWSEINFO m_bi;

    m_bi.ulFlags = BIF_RETURNONLYFSDIRS  | BIF_STATUSTEXT;
    m_bi.hwndOwner = hWnd;
    m_bi.pidlRoot = NULL;
    m_bi.lpszTitle = lpTitle;
    m_bi.lpfn = NULL;
    m_bi.lParam = NULL;
    m_bi.pszDisplayName = szPath;

    LPITEMIDLIST pidl = ::SHBrowseForFolder( &m_bi );
    if ( pidl )
    {
        if( !::SHGetPathFromIDList ( pidl, szPath ) )  szPath[0]=0;

        IMalloc * pMalloc = NULL;
        if ( SUCCEEDED ( ::SHGetMalloc( &pMalloc ) ) )  // 取得IMalloc分配器接口
        {
            pMalloc->Free( pidl );    // 释放内存
            pMalloc->Release();       // 释放接口
        }
    }
    return szPath;
}

示例三、在窗口中显示一幅 JPG 图象。

void CxxxView::OnDraw(CDC* pDC)
{
	::CoInitialize(NULL);  // COM 初始化
	HRESULT hr;
	CFile file;

	file.Open( "c:\\aa.jpg", CFile::modeRead | CFile::shareDenyNone );  // 读入文件内容
	DWORD dwSize = file.GetLength();
	HGLOBAL hMem = ::GlobalAlloc( GMEM_MOVEABLE, dwSize );
	LPVOID lpBuf = ::GlobalLock( hMem );
	file.ReadHuge( lpBuf, dwSize );
	file.Close();
	::GlobalUnlock( hMem );

	IStream * pStream = NULL;
	IPicture * pPicture = NULL;

	// 由 HGLOBAL 得到 IStream,参数 TRUE 表示释放 IStream 的同时,释放内存
	hr = ::CreateStreamOnHGlobal( hMem, TRUE, &pStream );
	ASSERT ( SUCCEEDED(hr) );

	hr = ::OleLoadPicture( pStream, dwSize, TRUE, IID_IPicture, ( LPVOID * )&pPicture );
	ASSERT(hr==S_OK);

	long nWidth,nHeight;  // 宽高,MM_HIMETRIC 模式,单位是0.01毫米
	pPicture->get_Width( &nWidth );    // 宽
	pPicture->get_Height( &nHeight );  // 高

	////////原大显示//////
	CSize sz( nWidth, nHeight );
	pDC->HIMETRICtoDP( &sz );  // 转换 MM_HIMETRIC 模式单位为 MM_TEXT 像素单位
	pPicture->Render(pDC->m_hDC,0,0,sz.cx,sz.cy,
		0,nHeight,nWidth,-nHeight,NULL);

	////////按窗口尺寸显示////////
//	CRect rect;	GetClientRect(&rect);
//	pPicture->Render(pDC->m_hDC,0,0,rect.Width(),rect.Height(),
//		0,nHeight,nWidth,-nHeight,NULL);

	if ( pPicture ) pPicture->Release();// 释放 IPicture 指针
	if ( pStream ) pStream->Release();  // 释放 IStream 指针,同时释放了 hMem

	::CoUninitialize();
}

示例四、在桌面建立快捷方式
在阅读代码之前,先看一下关于“快捷方式”组件的结构示意图。


图二、快捷方式组件的接口结构示意图

从结构图中可以看出,“快捷方式”组件(CLSID_ShellLink),有3个(其实不止)接口,每个接口完成一组相关功能的函数。IShellLink 接口(IID_IShellLink)提供快捷方式的参数读写功能(见图三),IPersistFile 接口(IID_IPersistFile)提供快捷方式持续性文件的读写功能。对象的持续性(注5),是一个非常常用,并且功能强大的接口家族。但今天,我们只要了解其中两函数,就可以了:IPersistFile::Save()和IPersistFile:Load()。(注6)


图三、快捷方式中的各种属性

#include < atlconv.h >
void CreateShortcut(LPCTSTR lpszExe, LPCTSTR lpszLnk)
{
	// 建立块捷方式
	// 参数 lpszExe: EXE 文件全路径名
	// 参数 lpszLnk: 快捷方式文件全路径名

	::CoInitialize( NULL );

	IShellLink * psl = NULL;
	IPersistFile * ppf = NULL;

	HRESULT hr = ::CoCreateInstance(  // 启动组件
		CLSID_ShellLink,      // 快捷方式 CLSID
		NULL,                 // 聚合用(注4)
		CLSCTX_INPROC_SERVER, // 进程内(Shell32.dll)服务
		IID_IShellLink,       // IShellLink 的 IID
		(LPVOID *)&psl );     // 得到接口指针

	if ( SUCCEEDED(hr) )
	{
		psl->SetPath( lpszExe );  // 全路径程序名
//		psl->SetArguments();      // 命令行参数
//		psl->SetDescription();    // 备注
//		psl->SetHotkey();         // 快捷键
//		psl->SetIconLocation();   // 图标
//		psl->SetShowCmd();        // 窗口尺寸

		// 根据 EXE 的文件名,得到目录名
		TCHAR szWorkPath[ MAX_PATH ];
		::lstrcpy( szWorkPath, lpszExe );
		LPTSTR lp = szWorkPath;
		while( *lp )    lp++;
		while( ''\\'' != *lp )    lp--;
		*lp=0;

		// 设置 EXE 程序的默认工作目录
		psl->SetWorkingDirectory( szWorkPath );

		hr = psl->QueryInterface(  // 查找持续性文件接口指针
			IID_IPersistFile,      // 持续性接口 IID
			(LPVOID *)&ppf );      // 得到接口指针

		if ( SUCCEEDED(hr) )
		{
			USES_CONVERSION;       // 转换为 UNICODE 字符串
			ppf->Save( T2COLE( lpszLnk ), TRUE );  // 保存
		}
	}
	if ( ppf )	ppf->Release();
	if ( psl )	psl->Release();

	::CoUninitialize();
}

void OnXXX()
{
	CreateShortcut(
		_T("c:\\winnt\\notepad.exe"),  // 记事本程序。注意,你的系统是否也是这个目录?
		_T("c:\\Documents and Settings\\Administrator\\桌面\\我的记事本.lnk")
	);
	// 桌面上建立快捷方式(lnk)文件的全路径名。注意,你的系统是否也是这个目录?
	// 如果用程序实现寻找桌面的路径,则可以查注册表
	// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
}


七、小结

本回介绍的内容比较实用。大家不要只抄袭代码,而一定要理解它。结合 MSDN 的说明去思索代码、理解其含义。好了,想方设法把代码忘掉!三天后(如过你还没有忘记,那就再过三天),你在不参考示例代码,但可以随便翻阅 MSDN 的情况下,自己能独立地再次完成这四个例程,那么恭喜你,你已经入门了:0) 从下回开始,我们要用 ATL 做 COM 的开发工作啦,您老人家准备好了吗?

作业,留作业啦……
1、你已经学会如何建立快捷方式了,那么你知道怎么读取它的属性吗?(如果写不出这个程序,那么你就不用继续学习了。因为……动点脑筋呀!我还没有见过象你这么笨的学生呢!)
2、示例程序三中使用了 IPicture 接口显示一个 JPG 图象。那么你现在去完成一个功能,把 JPG 文件转换为 BMP 文件。


注1:智能指针的概念和用法,后续介绍。
注2:IDL 文件,下回就要介绍啦。
注3:东北话,想干什么都可以,反正我不管啦。
注4:聚合,也许在第30回中介绍吧:-)
注5:持续性,IPersistXXXXXX是一个非常强大的接口家族,后续介绍。
注6:想知道 IShellLink、IPersistFile接口的所有函数吗?别愣着,快去看MSDN呀……
最新评论 [发表评论] [文章投稿] 查看所有评论 推荐给好友 打印
好奇怪,我做了老师的作业,先用IPicture通过IStream对象去读一个jpg文件.然后再把这个IPicture通过一个IStream对象写到一个Buffer里,再通过这个Buffer写到一个bmp文件中。可是为什么原来那个JPG文件1.7M,可是写到bmp文件里还是1.7M?我感觉图像格式并没有变。 ( smallkey 发表于 2008-5-8 1:07:00)

相见恨晚呀! ( wl0008 发表于 2007-7-3 16:39:00)

写得到太好,深入淺出。 ( ytfrdfiw 发表于 2007-4-22 14:10:00)

我想问杨老师一个问题:
工程引用在vc6++怎么实现 ( lycnet 发表于 2007-3-4 14:40:00)

顶……..非常的好!teacher Yang 的文章和《COM技术内幕》结合起来看我觉得不错!
郑重申明:个人愚见 ( Johnason 发表于 2006-9-12 16:28:00)

杨老师,谢谢您!!! ( goxigo 发表于 2006-8-23 17:43:00)

写的好啊,太谢谢了。。
只恨见到太晚。。。
不过老师就是老师,总爱留作业 ;) ( maxxfire 发表于 2006-6-10 11:00:00)

如何在一个方法中实现两个出参数:[out]BSTR* BSTR1,BSTR* BSTR2??
很急!谢谢大虾.
还有,一个接口方法中能不能使用两个以上的CoTaskMemAlloc??我使用一个可以正常交互;使用两个的时候在客户端得到的数据为空.
毕业设计赶着要用.谢谢大虾的帮忙
我的油箱:liziwen1982@163.com
QQ:87052309
谢谢交流 ( liziwen1982 发表于 2006-5-1 17:29:00)

疑问: 为什么void CUse1Dlg::OnButton1() 中需要
if( s3 ) ::SysFreeString( s3 );  //IFun::Cat()最后一个参数是 [out] 方向属性,因此调用者要释放内存, 不理解是什么意思啊!!!

每一个new() 对应 一个delete(), 那么跟SysFreeString()对应的操作是什么呢, 在哪里分配的内存?? ( ding_net 发表于 2006-4-29 21:45:00)

void CTestCom1Dlg::GetAttribute( LPCSTR szLnk )
{
IShellLink * psl = NULL;
IPersistFile * ppf = NULL;
HRESULT hr = ::CoCreateInstance(  // 启动组件
CLSID_ShellLink,      // 快捷方式 CLSID
NULL,                 // 聚合用(注4)
CLSCTX_INPROC_SERVER, // 进程内(Shell32.dll)服务
IID_IShellLink,       // IShellLink 的 IID
(LPVOID *)&psl );     // 得到接口指针

if ( SUCCEEDED(hr) )
{
hr = psl->QueryInterface(  // 查找持续性文件接口指针
IID_IPersistFile,      // 持续性接口 IID
(LPVOID *)&ppf );      // 得到接口指针

if ( SUCCEEDED(hr) )
{
USES_CONVERSION;
ppf->Load( T2COLE( szLnk ) , 0 ) ;

TCHAR pszAtt[ 1024 ] ;
WIN32_FIND_DATA pfd ;
psl->GetPath( pszAtt , sizeof( pszAtt ) , &pfd , SLGP_SHORTPATH ) ;
MessageBox( pszAtt ) ;
}
}

if ( ppf ) ppf->Release();
if ( psl ) psl->Release();
} ( xiongxiongVC 发表于 2006-1-26 17:54:00)

……………………………………………….
More…

有关COM接口的参数属性(in、out、retval)的解释

对于in类型的参数,由调用者创建,COM组件使用,但是不会改变参数的值。
【in,out】类型的参数是由调用者创建,并由调用者分配内存,COM组件修改 内存中的数据供调用者使用。
【out,retval】类型的参数是由COM组件创建并分配内存,返回给调用者使用,调用者不能修改内存数据。

在html页面中如果比较数据JavaScript可以使用【in,out】的参数,一般使用【out,retval】参数。
在C#代码中可以使用【in,out】参数

CodeProject: .NET – COM Interoperability. Free source code and programming help
http://www.codeproject.com/KB/COM/COM_DOTNET_INTEROP.aspx

Summary

This paper provides the technical overview of .NET and COM interoperability. It describes how .NET components can communicate with existing COM components without migrating those COM components into .NET components, thus helping the migration cost and business systems. This paper also provides an overview of marshalling. The intended audience is a development team that wishes to interact with COM and .NET applications. (This paper assumes that the reader has the fundamental knowledge of COM and .NET)

Introduction

From the time Microsoft engineers started working on the ideas behind COM in 1998, COM went through quite an evolution. Once .NET was released everything was about the CLR. Those business systems made lot of investments on those COM developments and they may not be willing to invest more money to build their components into .NET. Also this will make a severe impact in productivity.

Fortunately, switching from COM to .NET involves no such radical loss of productivity. The concept of providing bridge between .NET and COM components is .NET-COM interoperability. Microsoft .NET Framework provides system, tools, and strategies that enable strong integration with past technologies and allow legacy code to be integrated with new .NET components. It provides a bridge between the .NET and COM and vice versa.

There are two key concepts that make it much easier to move from COM development to .NET development, without any loss of code base or productivity.

  • Interaction with COM components from .NET
  • Interaction with .NET components from COM

Before going further, this paper will describe about the basic communication fundamentals of COM and .NET components.

Communication between Object and Client

COM is a binary reusable object which exposes its functionality to other components. When a client object asks for instances of server object, the server instantiates those objects and handout references to the client. So, a COM component can act as a binary contract between caller and callee. This binary contract is defined in a document known as Type library. The Type library describes to a potential client the services available from a particular server. Each COM components will expose a set of interfaces through which the communication between COM components will occurs.

The following diagram shows the communication between a client and a COM object.

Fig.1 Communication between client and a COM object

In the above figure the IUnknown and IDispatch are the interfaces and QueryInterface, AddRef, Release, etc., are the methods exposed by those interfaces.

The communication between the .NET objects occurs through Objects, there are no such interfaces for communication. So, in .NET component, there is no type libraries, instead they deal with assemblies. Assembly is a collection of types and resources that are built to work together and form a logical unit of functionality. All the information related to the assembly will be held in assembly metadata. Unlike the communication between COM components, the communication between .NET components is Object based.

Calling COM components from .NET Client

Generally COM components will expose interfaces to communicate with other objects. A .NET client cannot directly communicate with a COM component because the interfaces exposed by a COM component may not be read by the .NET application. So, to communicate with a COM component, the COM component should be wrapped in such a way that the.NET client application can understand the COM component. This wrapper is known as Runtime Callable Wrapper (RCW).

The .NET SDK provides Runtime Callable Wrapper (RCW) which wraps the COM components and exposes it into to the .NET client application.

Fig.2 calling a COM component from .NET client

To communicate with a COM component, there should be Runtime Callable Wrapper (RCW). RCW can be generated by using VS.NET or by the use of TlbImp.exe utility. Both the ways will read the type library and uses System.Runtime.InteropServices.TypeLibConverter class to generate the RCW. This class reads the type library and converts those descriptions into a wrapper (RCW). After generating the RCW, the .NET client should import its namespace. Now the client application can call the RCW object as native calls.

When a client calls a function, the call is transferred to the RCW. The RCW internally calls the native COM function coCreateInstance there by creating the COM object that it wraps. The RCW converts each call to the COM calling convention. Once the object has been created successfully, the .NET client application can access the COM objects as like native object calls.

Calling .NET components from COM Client

When a COM client requests a server, first it searches in the registry entry and then the communication starts. Calling a .NET component from a COM component is not a trivial exercise. The .NET objects communicate through Objects. But the Object based communication may not be recognized by the COM clients. So, to communicate with the .NET component from the COM component, the .NET component should be wrapped in such a way that the COM client can identify this .NET component. This wrapper is known as COM Callable Wrapper (CCW). The COM Callable Wrapper (CCW) will be used to wrap the .NET components and used to interact with the COM clients.

CCW will be created by the .NET utility RegAsm.exe. This reads metadata of the .NET component and generates the CCW. This tool will make a registry entry for the .NET components.

Fig.3 calling a .NET component from COM client

Generally COM client instantiates objects through its native method coCreateInstance. While interacting with .NET objects, the COM client creates .NET objects by coCreateInstance through CCW.

Internally, when coCreateInstance is called, the call will redirect to the registry entry and the registry will redirect the call to the registered server, mscoree.dll. This mscoree.dll will inspect the requested CLSID and reads the registry to find the .NET class and the assembly that contains the class and rolls a CCW on that .NET class.

When a client makes a call to the .NET object, first the call will go to CCW. The CCW converts all the native COM types to their .NET equivalents and also converts the results back from the .NET to COM.

Programming model comparison of .NET-COM interoperability

The following table compares the .NET and COM based component programming models.

.NET COM
Object based communication Interface based communication
Garbage Collector to manage memory Reference count will be used to manage memory
Type Standard objects Binary Standard objects
Objects are created by normal new operator Objects are created by coCreateInstance
Exceptions will be returned HRESULT will be returned
Object info resides in assembly files Object info resides in Type library

Before the application starts to communicate, there are some technical constraints associated with this. When an object is transmitted to a receiver which is in a separate machine/process (managed/unmanaged) space, the object may need to undergo a transformation according to the native type to make it suitable for use by the recipient. That is the object will be converted into a recipient readable form. This process of converting an object between types when sending it across contexts is known as marshaling. The next section of the paper will gives an overview of marshalling in .NET.

.NET Marshalling

Thus .NET runtime automatically generates code to translate calls between managed code and unmanaged code. While transferring calls between these two codes, .NET handles the data type conversion also. This technique of automatically binding with the server data type to the client data type is known as marshalling. Marshaling occurs between managed heap and unmanaged heap. For example, Fig.4 shows a call from the .NET client to a COM component. This sample call passes a .NET string from the client. The RCW converts this .NET data type into the COM compatible data type. In this case COM compatible data type is BSTR. Thus the RCW converts the .NET string into COM compatible BSTR. This BSTR will be passed to the object and the required calls will be made. The results will be returned to back to the RCW. The RCW converts this COM compatible result to .NET native data type.

Fig.4 Sample diagram for marshalling

Logically the marshalling can be classified into 2 types.

  1. Interop marshalling
  2. COM marshalling

If a call occurs between managed code and unmanaged code with in the same apartment, Interop marshaler will play the role. It marshals data between managed code and unmanaged code.

In some scenarios COM component may be running in different apartment threads. In those cases i.e., calling between managed code and unmanaged code in different apartments or process, both Interop marshaler and COM marshaler are involved.

Interop marshaler

When the server object is created in the same apartment of client, all data marshaling is handled by Interop marshaling.

Fig.5 Sample diagram for same apartment marshalling

COM marshaler

COM marshaling involved whenever the calls between managed code and unmanaged code are in different apartments. For eg., when a .NET client (with the default apartment settings) communicates with a COM component (whichever developed in VB6.0), the communication occurs through proxy and stub because both the objects will be running in different apartment threads. (The default apartment settings of .NET objects are STA and the components which are developed by VB6.0 are STA). Between these two different apartments COM marshaling will occurs and with in the apartment Interop marshaling will occurs. Fig.6 shows this kind of marshaling.

This kind of different apartment communication will impact the performance. The apartment settings of the managed client can be changed by changing the STAThreadAttribute / MTAThreadAttribute / Thread.ApartmentState property. Both the codes can run in a same apartment, by making the managed code’s thread to STA. (If the COM component is set as MTA, then cross marshaling will occurs.)

Fig.6 Sample diagram for cross apartment marshalling

In the above scenario, the call with in different apartments will occur by COM marshaling and the call between managed and unmanaged code will occur by Interop marshaling.

Conclusion

Thus the communication between .NET applications and COM applications occurs through RCW and CCW.

As you have seen, COM applications can implement .NET types to achieve type compatibility or a .NET type can implement COM interfaces to achieve binary compatibility with related coclasses.

Although the managed clients can interact with the unmanaged objects, the managed client expects that the unmanaged object should act exactly the same as managed object.

When developing against the unmanaged component through COM interoperability, managed code developers will not be able to use some features of .NET like parameterized constructors, static methods, inheritance, etc., migrating an existing component or writing a managed wrapper will make the component easier to use for managed code developers. In some cases, the developer wants to migrate parts of the application to .NET so that application can take advantage of the new features that the .NET Framework offers. For example, ASP .NET provides advanced data binding, browser-dependent user interface generation, and improved configuration and deployment. The designer should evaluate when the value of bringing these new features in to the application outweigh the cost of code migration.

References

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

KRISHNA PRASAD.N
Occupation: Web Developer
Location: United States United States

Other popular COM / COM+ articles:


加关注

Get every new post delivered to your Inbox.