使用.NET 向浏览器写入二进制文件
admin 发表于: 2008-9-07 10:22 来源: pdf之家
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();
}
http://www.haopdf.cn/viewthread-2281.html
Java技巧:怎样从servlet打开一个非html文件(如PDF)
admin 发表于: 2008-9-12 08:26 来源: pdf之家
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文档是一件容易,方便的方式来提供给你的用户更多的信息。
2006-05-11 16:01:56
在.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>
http://www.planetpdf.com/developer/article.asp?ContentID=introducing_soap&gid=6324
Introducing SOAP
Dave Wraight Planet PDF Contributing Editor
March 18, 2004
|
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:
- Connection Object created between Acrobat and the Web Service
- Web Service Functions called
- User entered data taken from Form text fields and wrapped as XML fragments
- Web Service process request and returns response wrapped in XML
- 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.
Topic
Messages
I assume your web service is returning data of type “xml” and not string
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
Thanks for the response. This issue is resolved.
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: 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.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
| VC++获得当前系统时间的几种方案 zz | |
|
http://www.diybl.com/course/4_webprogram/asp.net/asp_netshl/2008111/96318.html
VC OCX 打包CAB 网页发布全过程记录

【本站开通在线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
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):
行了,我们就是怎么简简单单就可以调用com组件的任何功能了。
不过我们要看到这种方法的不足,由于这里用了迟绑定,因此我们无法让编译器做任何的类型检查工作,因此只有在运行时才能知道程序对错;而且,可以以这种方法调用的com组件必须实现IDispatch接口,也就是说必须是一个自动化组件,假如你要调用的组件是一个普通的com组件的话,那就一边哭去吧!呵呵
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
SYMPTOMS
When you call apartment-threaded components from an ASP.NET page in ASPCOMPAT m…
CAUSE
If you use ASPCOMPAT mode (that is, if you use a page with the <%@ ASPCOMPAT=”t…
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…
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.
REFERENCES
For additional information, click the article number below to view the article i…
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 |
http://www.codeproject.com/KB/cs/ActiveX_controls_in_C_.aspx
http://www.codeproject.com/KB/cs/importactivex.aspx
PRB: 灾难性故障错误使用 ActiveX 控件
本页
症状
从 Java, 试图使用 VisualC++ 生成 ActiveX 控件时试图运行 Java 应用程序时将看到以下错误: 错误: <0x8000ffff>…
解决方案
当试图使用 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。 这将创建称…
复现行为的步骤
- 生成并注册 Circ3.ocx 示例随 VisualC++ 附带。
- 运行 JACTIVEX /javatlb circ3.ocx。 这将创建称为 circ3 % windir%\java\trustlib, 将包含相应 coclass, .java 文件对于 CIRC3.OCX 接口下一个文件夹。
- 如下创建 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(); } } - 生成 for Java 2.0 以使用附带 JVC x 或更高 Java 应用程序。 有关如何将此 JVC 与 VisualJ++, 请参阅下面参考部分。
- 将看到上面提到的错误消息。
参考
有关如何使用 ActiveX 控件用作自动化服务器, 请参阅下列 Microsoft 知识库文章: 146120 (http://support.micr...
有关如何对 VisualJ++, 使用新 Jvc.exe 请参阅下列 Microsoft 知识库文章:
这篇文章中的信息适用于:
- 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 |
http://www.codeproject.com/KB/COM/opcdotnet.aspx

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):
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:
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:
[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:
... 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 |
|
Other popular COM / COM+ articles:
|
http://topic.csdn.net/t/20020918/21/1035190.html
请问,在ASP下如何调用OCX控件,高分求救
请问,在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
相关问题
http://topic.csdn.net/t/20020729/12/907605.html
谁有asp调用activex函数的代码
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
相关问题
http://topic.csdn.net/t/20060303/15/4591007.html
ASP中是不是不能调用带有界面的ocx控件?
现有一个带界面的用于处理图片的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
相关问题
http://hi.baidu.com/appleluree/blog/item/8bdabbdef505635795ee377d.html
|
查看文章
|
|
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模式或其它系统替换正常文件即可解决。 |
|
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。 我想请大虾指点一下,我如何在页面中能看到这个控件,在asp.cs中又能得到它,就象使用其他控件一样使用它? 回答: 1、把这个控件用命令转换成dll文件,然后引入就OK了。 2、在ASP。NET中使用OCX一般分以下几个步骤: |
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对象的方法和属性名称
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.UCOMITypeLib 和 System.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之类的方法想来有兴趣的人也不多,不过反正这种底层方法就那么几个,在你遍历的时候尽可以判断一下过滤掉这些方法名称。
免责声明:
在本文中,为了清晰起见,所有给出的代码中都没有错误处理。如果你在你的代码中使用本文中的部分代码,由此造成的诸如程序出错、系统宕机、走路撞树、手机爆炸、洪水毁堤、地球毁灭等等一切后果,本人概不负责
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:
- Open VS.NET2003->New Project->Visual C# Projects->Class Library.
- Project name: MyInterop.
- Create MyDoNetClass.cs file, and add the following lines of code:
Collapseusing System.Runtime.InteropServices; using System.Windows.Forms;
- Create an Interface
IMyDotNetInterface. - Create a class
MyDoNetClass. - 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.

- Now, create a GUID for the Interface, and add the following line for the interface:
Collapse[Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
- Now, create a GUID for the class, and add the following line for the class:
Collapse[Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
- Your code will look like:
Collapseusing 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”); } } }
- Compile the solution.
- 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.
- Hard-code a specific version number in your
AssemblyVersionattribute in the AssemblyInfo.cs file which is in your project.Example:
Collapse[assembly: AssemblyVersion("1.0.0.0")]
- Create a strong-name key pair for your assembly and point to it via the
AssemblyKeyFileattribute in the AssemblyInfo.cs file which is in your project. Example:
Collapsesn -k TestKeyPair.snk
Collapse[assembly: AssemblyKeyFile("TestKeyPair.snk")]
- Add your assembly to the GAC using the following command:
Collapsegacutil /i MyInterop.dll
- Register your assembly for COM by using the REGASM command along with the “/tlb” option to generate a COM type library.
CollapseREGASM MyInterop.dll /tlb:com.MyInterop.tlb
- Close the C# project.
Steps to create an Unmanaged C++ application to call a .NET Managed C# COM
- Open VS.NET2003->New Project->Visual C++ Projects->Win32->Win32 Console Project.
- Name: DotNet_COM_Call.
- Include the following line in your DoNet_COM_Call.cpp file:
Collapse#import “<Full Path>\com.MyInterop.tlb" named_guids raw_interfaces_only
- Compile the solution.
- It will generate a “com.myinterop.tlh” file into your project->debug directory.
- You can open this file and see the contents. This is basically the proxy code of the C# COM code.
- Now, you can write the code to call the .NET Managed COM.
- Please add the following lines of code before calling the COM exported functions:
CollapseCoInitialize(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
- Run this console application.
- 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.
|
Other popular C# articles:
|
http://topic.csdn.net/t/20040427/17/3014084.html
请问.odl和.idl有什么区别啊?
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” 的方式包含后者. 反过来没有试过.
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
相关问题
|
| ::首页 >> 文档中心 >> 在线杂志 >> COM技术(COM/DCOM/COM+) | [ 在线杂志 第43期 ] | |
|
每一个new() 对应 一个delete(), 那么跟SysFreeString()对应的操作是什么呢, 在哪里分配的内存?? ( ding_net 发表于 2006-4-29 21:45:00)
if ( SUCCEEDED(hr) ) if ( SUCCEEDED(hr) ) TCHAR pszAtt[ 1024 ] ; if ( ppf ) ppf->Release(); ………………………………………………. |
对于in类型的参数,由调用者创建,COM组件使用,但是不会改变参数的值。
【in,out】类型的参数是由调用者创建,并由调用者分配内存,COM组件修改 内存中的数据供调用者使用。
【out,retval】类型的参数是由COM组件创建并分配内存,返回给调用者使用,调用者不能修改内存数据。
在html页面中如果比较数据JavaScript可以使用【in,out】的参数,一般使用【out,retval】参数。
在C#代码中可以使用【in,out】参数
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.
- Interop marshalling
- 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 |
|
Other popular COM / COM+ articles:
|
Back to the top

回到顶端



