Praveen Katiyar' Blog

Learning along the way . . . .

Creating Simple WCF Service with IIS Hosting

In this post I am going to explain how to create a simple WCF Service, with IIS Hosting and consume it, there will be two parts of the project.

  • A WCF Service (MyMathService.svc): will be hosted by IIS.
  • Client Application (MyMathClient.exe): Client Application which will use this service.

let’s start with creating the WCF Service.

Creating the WCF Service

Start the Visual Studio 2010 in administrator Mode (Run as Administrator), and click File->New->Web Site. Select the project template ‘WCF Service’ and Location as http. This will directly host the service in IIS and click OK. select the template “WCF Service”. 

image

Now let’s analyse the project created by wizard for us, and do little house keeping, before we write any code.

  • IService.cs (the interface definition of the service)
  • Service.cs (the implementation of the service).
  • web.config (Service configuration file).
  • Service.svc

Assumption

We are going to create a Service as per following assumptions.

  • Service will be named as "MyMathService" (MyMathService.svc)
  • Interface will named as IMyMathService (IMyMathService.cs)
  • Service will be implemented as MyMathService (MyMathService.cs)
  • Service will implement Http endpoint at Port 8001.
  • Service will also expose IMetadataExchange endpoint.  IMetadataExchange interface Exposes methods used to return metadata about a service.

Little house keeping. (just to keep things organized)

  • Rename IService.cs as IMyMathService.cs.
  • Rename Service.cs as MyMathService.cs.
  • Rename Service.svc as MyMathService.svc, and change its content as

Previous Content

<%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

New Content

<%@ ServiceHost Language="C#" Debug="true" Service="MyMathService" CodeBehind="~/App_Code/MyMathService.cs" %>

Defining Configuration File

Changing web.config file.

Below is the listing of the configuration file, generated by visual studio wizard, as we know, that Services are defined in <System.servicemodel> section. Below is the listing of the configuration file, generated by visual studio wizard.  let’s define a service and endpoint, see the highlighted part.

<?xml version="1.0"?>
<configuration>

                 <configSections>
        . . . . . . . . .
         . . . . . . . . .
      </configSections>

    <system.web>
     . . . . . . . . .
     . . . . . . . . .
    </system.web>

  <system.serviceModel> 
<services>
     <service name="MyMathService" behaviorConfiguration="svcBehavior">  
        
<endpoint address=http://localhost:8001/MyMathService/MyMathService.svc" binding="wsHttpBinding" contract="IMyMathService">

          <identity> <dns value="localhost"/> </identity>
</endpoint>

      <endpoint address ="MEX" binding ="mexHttpBinding" contract="IMetadataExchange" /> 
   </service> 
</services>

   <behaviors>
      <serviceBehaviors>
        <behavior  name="svcBehavior">
          <!– To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment –>
         <serviceMetadata httpGetEnabled="true"/>
          <!– To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information –>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
   
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel> 

<system.codedom>
         . . . . . . . . .
         . . . . . . . . .
      </system.codedom>

   <system.webServer>
         . . . . . . . . .
         . . . . . . . . .
   </system.webServer>    

   <runtime>
         . . . . . . . . .
         . . . . . . . . .
   </runtime>

 
</configuration>

Explanation

See the highlighted text, as you can see service defines two endpoints, one is first end point defines an address(http://localhost:8001/MyMathService), binding(HTTP) and contract (IMyMathService), the other is MEX endpoint, MEX endpoint are defined to import Metadata (to be used by client applications) from a Service using utility SVCUtil.exe

<endpoint address ="http://localhost:8001/MyMathService&quot; binding ="basicHttpBinding" contract="IMyMathService" />

<endpoint address ="MEX" binding ="mexHttpBinding" contract="IMetadataExchange" />

In the serviceBehaviors, a behavior named "svcBehavior" defines following attributes about the service.

<serviceMetadata httpGetEnabled="true"/>

metadata information about the service can disclosed through a get request (if this is false, SVCUtil.exe would not be able to obtain metadata information about the service).

<serviceDebug includeExceptionDetailsInFaults="true"/>

can be set true, to receive exception details in faults for debugging purposes, should be set to false, before deployment, to avoid disclosing exception information.

Defining Service Interface (IMyMathService.cs)

using System;
using System.ServiceModel;
using System.Text;

[ServiceContract]
public interface IMyMathService
{
    [OperationContract]
    double Add(double dblNum1, double dblNum2);

    [OperationContract]
    double Subtract(double dblNum1, double dblNum2);

    [OperationContract]
    double Multiply(double dblNum1, double dblNum2);

    [OperationContract]
    double Divide(double dblNum1, double dblNum2);
}

explanation

as one can see, there is one service contract (IMyMathService), and 4 operation contract to perform 4 basic math operations.

Implementing Service (MyMathService.cs)

using System;
using System.ServiceModel;
using System.Text;

public class MyMathService : IMyMathService
{
    public double Add(double dblNum1, double dblNum2)
    {
        return (dblNum1 + dblNum2);
    }

    public double Subtract(double dblNum1, double dblNum2)
    {
        return (dblNum1 – dblNum2);
    }

    public double Multiply(double dblNum1, double dblNum2)
    {
        return (dblNum1 * dblNum2);
    }

    public double Divide(double dblNum1, double dblNum2)
    {
        return ((dblNum2 == 0) ? 0 : (dblNum1 / dblNum2));
    }
}

explanation

here simply those 4 methods has been implemented.

Creating Client for the Service

Add a new project to the workspace, say a Console based application, name it MyMathClient, for instance.

image

newly created project will be added to the work space.

Generating proxy and config file.

right click on the newly created (client) project, and click on "Add Service Reference", as shown below.

image

a dialog box will be displayed as shown below. in the address bar type the address of the service,

image

Click OK,

  • A app.config (client side configuration) will be added to the project.
  • a Service reference named MyMathServiceProxy will be added in Service References node of the client project.

Calling the Service

Now write the code to use the proxy and call the service, here is the listing of the Program.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyMathClient
{
    class Program
    {
        static void Main(string[] args)
        {
            double dblX = 2000.0 ;
            double dblY = 100.0 ;
            double dblResult = 0 ;
            MyMathServiceProxy.MyMathServiceClient mathClient = new MyMathServiceProxy.MyMathServiceClient();

            dblResult = mathClient.Add (dblX, dblY );
            Console.WriteLine("Calling Add >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);
           
            dblResult = mathClient.Subtract (dblX, dblY);
            Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

            dblResult = mathClient.Multiply(dblX, dblY);
            Console.WriteLine("Calling Mul >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);

            dblResult = mathClient.Divide(dblX, dblY);
            Console.WriteLine("Calling Sub >>  X : {0:F2}  Y : {1:F2}  Result : {2:F2}", dblX, dblY, dblResult);
        }
    }
}

and here is the output.

image

Creating a web Client for the Service

Add a new web site to the workspace, name it MyWebMathClient, for instance as shown below.

image

Add Service reference of the Math Service to the newly created website, as shown below

image

Adding this Service Reference, made a change in the web.config file of the Client Web site, if you open the web.config, you will find the following changes, at the bottom of the file.

<system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IMyMathService" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="
http://localhost/MyMathService/MyMathService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyMathService"
                contract="MyMathServiceReference.IMyMathService" name="WSHttpBinding_IMyMathService">
                <identity>

                   <!—this name can be different on your machine. –!>
                    <servicePrincipalName value="host/PRAVEEN-WIN7" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

 

Open the Page_load Handler of the Default.aspx in the newly created (Client Web Site) and put the code as shown below.

protected void Page_Load(object sender, EventArgs e)
   {
       double dblX = 10000.0;
       double dblY = 2000.0;
       double dblResult = 0;
       Response.Write("<p>Value 1 : " + dblX.ToString("F2"));
       Response.Write("<br>Value 2 : " + dblY.ToString("F2"));

       try
       {
           Response.Write("<p>Using WS HTTP Binding");

           MyMathServiceReference.MyMathServiceClient mathProxy2 = new MyMathServiceReference.MyMathServiceClient("WSHttpBinding_IMyMathService");

           dblResult = mathProxy2.Add(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Subtract(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Multiply(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));

           dblResult = mathProxy2.Divide(dblX, dblY);
           Response.Write("<br>Calling Add >>  X : " + dblX.ToString("F2") + "  Y : " + dblY.ToString("F2") + " Result : " + dblResult.ToString("F2"));
       }
       catch (Exception eX)
       {
           Response.Write("There was an error while calling Service <p> <b>[" + eX.Message + "] </b>");
       }
   }

and when you run this web site, you will get following output.

image

Advertisements

September 6, 2013 Posted by | .NET, CodeProject, SOA, WCF | , , , | 1 Comment

Introduction to WCF

What is WCF

In a nutshell, WCF is a SDK for developing and deploying services on Windows, although services can be build even without WCF.  Developing services with WCF is easier. WCF is Microsoft’s implementation of a set of industry standards defining service interactions, type conversions, marshaling, and management of various protocols. consequently, WCF provides interoperability between services.    

What is SOA

SOA is the next evolutionary step in the long journey from functions to object to components to service orientated applications. Service orientation (SO) is an abstract set of methodologies, principles and best practices for building service oriented applications(SOA). Service oriented application aggregates services into a single logical application.

What is a Service

A service is a unit of functionality exposed to the world. the services can be local or remote, can be deployed by multiple parties using any technology.

What is a WCF Service

WCF Service typically exposes metadata describing the available functionality and possible ways of communicating with service. Metadata is published in a predefined, technology-neutral way such as using WSDL (Web Services Description Language) over HTTP-GET or an industry standard for metadata exchange over any protocol. WCF services may communicate over a variety of transports (not just HTTP). A non WCF client can import the metadata to its native environment as native types. similarly, a WCF client can import the metadata of a non WCF service and  consume it as a native CLR class/interface. 

Anatomy of WCF Service/ A B C of WCF Service

(A) Address

in WCF every service is associated with a unique address. the address provides two important elements:

  • location of the service: the location portion of the address indicates the name of the target machine, site, or network; a communication port, pipe or queue; and an optional specific path, or URI. URI can be any unique string, such as service name or a globally unique identifier (GUID).

  • transport protocol/transport scheme: WCF supports following transport protocols/schemes.

    • HTTP/HTTPS

    • TCP

    • IPC

    • Peer network

    • MSMQ

    • Service Bus

the address always have the following format

[base address] / [optional URI]

the base address is always in the format

[transport]://[machine or domain][optional port]

here are few examples of  sample addresses.

http://localhost:8001                              

http://localhost:8001/MyService           

net.tcp://localhost:8002/MyService      

net.pipe://localhost/MyPipe                   

net.msmq://localhost/MyQueue             

here are few examples of  sample addresses.

(B) Binding

A binding is merely, a consistent, canned set of choices regarding the transport protocol, message encoding, communication pattern, reliability, security, transaction propagation and interoperability. A single service can support multiple bindings on separate addresses. Binding allow you to use the same service logic over drastically different plumbing. all you need to do is determine the target scenario for your service, and WCF makes a correct multidimensional decision for you regarding all the aspects of the communication. One can use the WCF-provided bindings out of the box, can tweak their properties, or can write their own custom bindings from scratch. WCF defines 5 frequently used bindings.

  • Basic Binding: offered by the BasicHttpBinding class, basic binding is designed to expose a WCF services as a legacy ASMX web service, so that old clients can work with the new services. this binding makes your service look like a legacy web service that communicates over basic web service profile. when used by clients, this enables new WCF clients to work with old ASMX services.
  • TCP Binding:  offered by NetTcpBinding class, TCP binding uses TCP for cross machine communication on the intranet. it supports variety of features, including reliability, transactions and security, and is optimized for WCF to WCF communication, hence it requires both the client and the service to use WCF.
  • IPC Binding: offered by NetNamedPipeBinding class, IPC binding uses named pipes as a transport for same-machine communication. it is the most secure binding, since it can not accept calls outside of the machine boundary. It is also the most performant binding, since IPC is a lighter protocol than TCP.
  • Web Service (WS) Binding: offered by WSHttpBinding class, the WS binding uses HTTP or HTTPS for transport and offers a variety of features(such as reliability, transactions, and security) over the Internet, all using the WS-* standards.
  • MSMQ Binding: offered by the NetMsmqBinding class, the MSMQ binding uses MSMQ for transport and offers support for disconnected queued calls. 

each frequently used binding  uses different transport scheme and encoding as shown below.

Name Transport Encoding Interoperable
BasicHttpBdinding HTPP/HTTPS TEXT, MTOM Yes
NetTcpBinding TCP Binary No
NetNamedPipeBinding IPC Binary No
WsHttpBinding HTTP/HTTPS TEXT, MTOM Yes
NetMsmqBidning MSMQ Binary No

having text based encoding typically enables a WCF service (or client) to communicate over HTTP with any other service (or client), regardless of its technology and across firewalls. Binary encoding over TCP, IPC or MSMQ yields the best performance, but it does so at the cost of interoperability because it mandates the WCF-WCF communication.

Choosing a Binding

When choosing a binding the following diagram can help.

image

in addition to the five frequently used bindings described above, WCF defines 6 infrequently used bindings. these bindings are each designed for a specific target scenario, which normally can not be used out of that scenario. 

  • WS dual binding:  offered by WSDualHttpBinding class, similar to the WS binding, except it also supports bidirectional duplex communication from the service to the client. This binding nothing more than just two WsHttpBinding bindings wired up against each other to support callbacks, as there is no industry standard for setting up callback, thus WSDualHttpBinding is not interoperable.
  • Peer Network binding: offered by NetPeerTcpBinding class, this uses peer networking as a transport: the peer network enabled client and services all subscribe to the same grid and broadcast messages to it.
  • Fedrated WS binding: offered by WSFedrationHttpBinding class, a specialization of WS binding that offers support for federated security, not a main stream binding. 
  • Fedrated WS 2007 binding: offered by WS2007FedrationHttpBinding class, this is an update of a WSFedrationHttpBinding.
  • MSMQ integration binding: offered by MSMQIntegrationBinding class, this is the analogous queued –world binding to the basic binding. The integration binding converts WCF messages to and from MSMQ messages and is designed to interoperate with legacy MSMQ clients.
  • WS 2007 binding: offered by WS2007HttpBinding class, this binding is derived from the WSHttpBinding class; it adds support for the emerging co-ordination standard and updates for the transaction, security, and reliability standards.

(C) Contracts

A WCF contract is a platform neutral and standard way of describing what a service does. in WCF all services expose contracts. WCF defines 4 types of contracts.

  • Service Contracts: Describes which related operations can be tied together as a single functional unit that the client can perform on the service. Service contracts can be defined as shown below.

    [ServiceContract]
    public interface IMyService
    {

    }

  • Operation Contract: An operation contract defines the parameters and return type of an operation.

    [ServiceContract]
    public interface IMyService
    {
       [OperationContract]
        double MultiplyNumber(double dblX, double dblY );   
       [OperationContract]
        double DivideNumber(double dblX, double dblY );  
    }

  • Data Contracts: Defines which data types are passed to and from the service. WCF defines implicit contracts for built in types such as int and string, but you can easily define explicit opt in data contracts for custom types.

    [DataContract]
    public class ErrorInfo
    {
        private string m_strError;
        private int m_nErrorCode;
       
       [DataMember]
        public string ErrorMessage
        {
            get { return m_strError; }
            set { m_strError = value; }
        }

       [DataMember]
        public int ErrorCode
        {
            get { return m_nErrorCode }
            set { m_nErrorCode = value; }
        }
    }

  • Fault Contracts: Defines which errors are raised by the service and how the service handles and propagates errors to the clients. Fault Contract provides documented view for error occurred in the service to client. This helps to easily identity the error.

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        double MultiplyNumber(double dblX, double dblY );   
        [OperationContract]
       [FaultContract(typeof(DevideByZeroException))]
        double DivideNumber(double dblX, double dblY );  
    }

  • Message Contracts: Allow the service to interact directly with messages. Message contracts can be types or un typed and are useful in interoperability cases when another party has already dictated some explicit (mostly proprietary) message format. 

    [MessageContract]
    public class ErrorDetails
    {
        [MessageHeader]
        public int  ErrorCode;
       
       [MessageBodyMember]
        public string ErrorMessage;
       [MessageBodyMember]
        public DateTime ErrorTime;
    }

Hosting

The WCF service class can not exist in void. every WCF service must be hosted in a Windows process called host process. a single host process can host multiple services, and the same service type can be hosted in multiple services.

Hosting Environment and Supported Bindings

Hosting Environment

Supported protocol

Windows console and form application

http, net.tcp, net.pipe, net.msmq

Windows service application (formerly known as NT services)

http, net.tcp, net.pipe, net.msmq

Web server IIS6

http, wshttp

Web server IIS7 – Windows Process Activation Service (WAS)

http, net.tcp, net.pipe, net.msmq

 

A summary of hosting options and supported features.

Feature

Self-Hosting

IIS Hosting

WAS Hosting

Executable Process/ App Domain

Yes

Yes

Yes

Configuration

App.config

Web.config

Web.config

Activation

Manual at startup

Message-based

Message-based

Idle-Time Management

No

Yes

Yes

Health Monitoring

No

Yes

Yes

Process Recycling

No

Yes

Yes

Management Tools

No

Yes

Yes

Endpoints

Every service is associated with an address that defines where the service is, a binding defines how to communicate with the service, and the contract defines what the service does. WCF formalizes this relationship in the form of endpoint. The endpoint is the coalition of address, binding and contract. So every endpoint must have all 3 elements, and the host exposes the endpoint. logically, endpoint is the interface of the service to the outside world. Every service must expose at least one business Endpoint, and each endpoint has exactly one contract. All endpoints on a service has unique addresses, and a single service can expose multiple endpoints.

Configuration of Endpoint

It is important to note nothing in the service code has to do with its service points. and they are always external to the service code. you can configure endpoints either administratively or programmatically.

Administrative Endpoint Configuration

<system.ServiceModel>
    <services>
        <service name="MyService">
            <endpoint address="http://localhost:8000/MyService&quot; binding ="wsHttpBinding" contract="IMyContract">
            <endpoint address="http://localhost:8001/MyService&quot; binding ="netTcpBinding" contract="IMyContract">
            <endpoint address="http://localhost:8002/MyService&quot; binding ="netTcpBinding" contract="IOtherContract">
        </service>
    </services>
</system.ServiceModel>

Programmatic Endpoint Configuration

ServiceHost host = new ServiceHost(typeof(MyService));
Binding httpBinding = new WSHttpBinding();
Binding tcpBinding = new NetTcpBinding();
host.AddServiceEndPoint( typeof (IMyContract), httpBinding, "
http://localhost:8000/MyService");
host.AddServiceEndPoint( typeof (IMyContract), tcpBinding, "net.tcp://localhost:8001/MyService");
host.AddServiceEndPoint( typeof (IMyOtherContract), tcpBinding, "net.tcp://localhost:8002/MyService");

Default Endpoints

If the service host does not define any end points (neither in configuration nor programmatically) but does provide at least one base address. WCF will by default add endpoints to the service. These are called default endpoints. WCF will add an endpoint per base address per contract, using the base address as the endpoint’s address. for HTTP WCF will use the basic binding. Note that default binding will affect the default endpoints. WCF will also name the endpoint by concatenating the binding name and the contract name.

consider the following example.

[ServiceContract]
interface IMyContract {
    //Interface Body
    … 
}

[ServiceContract]
interface IMyOtherContract {
    //Interface Body
    … 
}

class MyService : IMyContract, IMyOtherContract {
    //Class Body
    … 
}

//    Host Application
Uri httpbaseAdr = new Uri ( "http://localhost:8000/");
Uri tcpbaseAdr = new Uri ( "net.tcp://localhost:9000/");
Uri pipebaseAdr = new Uri ( "net.pipe://localhost/");
ServiceHost host = new ServiceHost ( typeof (MyService), httpbaseAdr, tcpbaseAdr, pipebaseAdr);
host.Open ();

Assuming that no config file is used to define any additional endpoints, WCF will add these default endpoints, as they were defined in config file.

<service name="MyService">


    <endpoint name="BasicHttpBinding_IMyContract" address="http://localhost:8000/" binding="basicHttpBinding" contract="IMyContract" />
    <endpoint name="NetTcpBinding_IMyContract" address="net.tcp://localhost:9000/" binding="netTcpBinding" contract="IMyContract" />
    <endpoint name="NetNamedPipeBinding_IMyContract" address="net.pipe://localhost/" binding="netNamedPipeBinding" contract="IMyContract" />
   
    <endpoint name="BasicHttpBinding_IMyOtherContract" address="http://localhost:8000/" binding="basicHttpBinding" contract="IMyOtherContract" />
    <endpoint name="NetTcpBinding_IMyOtherContract" address="net.tcp://localhost:9000/" binding="netTcpBinding" contract="IMyOtherContract" />
    <endpoint name="NetNamedPipeBinding_IMyOtherContract" address="net.pipe://localhost/" binding="netNamedPipeBinding" contract="IMyOtherContract" />

</service>   

Metadata Exchange

By default, the service will not publish its metadata. publishing you service meta data will need some efforts. , luckily, the host can do it for you, if you instruct it to do so, as host knows everything, it needs to know about your service and its endpoints.

Enabling Metadata exchange administratively

<system.ServiceModel>
<services>
    <service name="MyService" behaviorConfiguration="MEXGET">
        <host>
        <baseAddresses>
            <add baseAddress = "net.pipe://localhost/" /> 
        </baseAddresses>
        
         <endpoint address="MEX" binding="mexNamedPipeBinding" contract="IMetadataExchange"/>

        <!– Here we have defined the complete address, we do not use the base address. -–>
        <endpoint address="http://localhost:8000/MEX" binding="mexHttpBinding" contract="IMetadataExchange"/>

        <endpoint address="net.tcp://localhost:8001/MEX" binding="mexTcpBinding" contract="IMetadataExchange"/>

    </service>   
</services>
</system.ServiceModel>

in the vast majority of cases, a MEX endpoint always has the same 3 elements: the contract is always IMetadataExchange, the binding is always the reserved binding element, and the only variable is the address (and that too, just the base address)

Adding MEX endpoints programmatically

like any other endpoint, you can also add metadata exchange endpoint programmatically before opening the host. WCF does not offer a dedicated binding type for the metadata exchange endpoint. you can use the following methods of MetadataExchangeBindings  class defined in System.ServiceModal.Description

Uri tcpbaseAdr = new Uri ( “net.tcp://localhost:9000/”);
ServiceHost host = new ServiceHost ( typeof (MyService), tcpbaseAdr );
ServiceMetadataBehavior metaBehave ;
metaBehave = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if ( metaBehave == null )
{
    metaBehave = new ServiceMetadataBehavior();
    host.Description.Behaviors.Add (metaBehave);
}
Binding binding = MetadataExchangeBindings.CreateMexTcpBinding ();
host.AddServiceEndpoint (typeof (IMetadataExchange), binding, "MEX");
host.Open ();

you can also add a MEX endpoint using the standard MEX endpoint.

ServiceHost host = new ServiceHost (typeof(MyService));
host.Description.Behaviors.Add(new ServiceMetadataBehavior());
EndpointAddress address = new EndpointAddress ( "
http://localhost:8000/MEX");
ServiceEndPoint endpoint = new ServiceMetadataEndPoint(address) ;
host.AddServiceEndpoint (endpont);
host.Open ();

Client side Programming

To invoke operations on a service, a client first need to import the service contract to client’s native (environ.) .

Client side Calling Service using Code

Just define the interface definition in the client application in a file, say IMyService.cs.

[ServiceContract]
public interface IMyService
{
   [OperationContract]
    double AddNumber(double dblX, double dblY );   
   [OperationContract]
    double MultiplyNumber(double dblX, double dblY );   
}

assuming that Service is hosted at address “http://localhost:8001/MyService/”

To invoke operations on a service, if you do not want to use a configuration file. a client need to create everything by hand.

private void CallServiceFunctionOnHTTP ()
{
    string strAdr =
http://localhost:8001/MyService/”;
    Uri adrbase = new Uri(strAdr);
    BasicHttpBinding httpb = new BasicHttpBinding();
    ChannelFactory<IMyService> channelFactory = new ChannelFactory<IMyService>(httpb);
   
    strEPAdr = "
http://localhost:8001/MyService" ;
    EndpointAddress ep = new EndpointAddress(strEPAdr );
    IMyService myObj = m_ChannelFactory.CreateChannel(ep);
    double dblResult = 0;
    dblResult = chatObj.AddNumber(dblX, dblY);
}

If the same Service also exposes another EndPoint (let say at "net.tcp://localhost:9000/MyService” ) then you can call the service, through this end point as shown below.

private void CallServiceFunctionOnTCP ()
{
    string strAdr =
net.tcp://localhost:9000/MyService/”;
    Uri adrbase = new Uri(strAdr);
    NetTcpBinding tcpb = new NetTcpBinding();
    ChannelFactory<IMyService> channelFactory = new ChannelFactory<IMyService>(tcpb);
   
    strEPAdr = "
net.tcp://localhost:9000/MyService
" ;
    EndpointAddress ep = new EndpointAddress(strEPAdr );
    IMyService myObj = m_ChannelFactory.CreateChannel(ep);
    double dblResult = 0;
    dblResult = chatObj.AddNumber(dblX, dblY);
}

August 20, 2013 Posted by | .NET, CodeProject, SOA, WCF | , , , , | Leave a comment

Modifying array of structures (default marshaling)

Let’s assume you have a user defined structure “EMPLOYEE” in a win32 DLL (let say it “Win32Native.dll”) as shown below.

typedef struct _EMPLOYEE
{
    int Age ;
    int Sex;
    double Salary ;
    char* FirstName ;
    char* LastName ;
} EMPLOYEE;

Define some functions in native dll (let say it “Win32Native.dll”)  as shown below. 

extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct(int nSize, EMPLOYEE* pArray);

Implementing Functions

extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct( int nSize, EMPLOYEE* pArray)
{
    int result = 0;
    EMPLOYEE* pCur = pArray;
    STRSAFE_LPSTR temp1, temp2 ;
    for ( int i = 0; i < nSize; i++ )
    {
        size_t nLen1 = 0;
        size_t nLen2 = 0;
        StringCchLengthA( pCur->FirstName, STRSAFE_MAX_CCH, &nLen1 );
        StringCchLengthA( pCur->LastName, STRSAFE_MAX_CCH, &nLen2 );
       
        nLen1 = sizeof(char) * ( nLen1 + 11 );    //    To accomodate "<Modified>"
        nLen2 = sizeof(char) * ( nLen2 + 11 );    //    To accomodate "<Modified>"
        temp1 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen1 );
        temp2 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen2 );

        StringCchCopyA( temp1, nLen1, (STRSAFE_LPCSTR)"<Modified>" );
        StringCbCatA( temp1, nLen1, (STRSAFE_LPCSTR)pCur->FirstName);

        StringCchCopyA( temp2, nLen2, (STRSAFE_LPCSTR)"<Modified>" );
        StringCbCatA( temp2, nLen2, (STRSAFE_LPCSTR)pCur->LastName);
               
        // CoTaskMemFree must be used instead of delete to free memory.
        CoTaskMemFree( pCur->FirstName  );
        CoTaskMemFree( pCur->LastName  );

        pCur->FirstName = (char *)temp1;
        pCur->LastName = (char *)temp2;

        pCur->Age += 1 ;
        pCur->Salary  += 1000.0 ;
        pCur++;
   }
}

Point of Interest

  • CoTaskMemAlloc is used to allocated the memory required.
  • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.
  • StringCchCopyA copies an ANSI string to a string buffer.
  • StringCbCatA Appends an ANSI string to a string buffer.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

  • On the native side use CoTaskMemAlloc() and CoTaskMemFree().

     

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct Employee
        {
            public int Age;
            public int Sex;
            public double Salary;
            public String FirstName;
            public String LastName;
        }
        class Program
        {
            [DllImport("Win32Native.dll")]

            public static extern int ModifyArrayOfEmployeeStruct(

                                                        int nSize,

                                                        [In, Out] Employee[] empArr);
            static void Main(string[] args)
            {
                int nCnt = 5; // Number of Items in Structure Array

                Employee[] emp = new Employee[nCnt];
                emp[0].FirstName = "Ramesh"; emp[0].LastName = "Sharma"; emp[0].Age = 42; emp[0].Salary = 40000; emp[0].Sex = 0;
                emp[1].FirstName = "Shalini"; emp[1].LastName = "Verma"; emp[1].Age = 30; emp[1].Salary = 25000; emp[1].Sex = 1;
                emp[2].FirstName = "Ramesh"; emp[2].LastName = "Sharma"; emp[2].Age = 51; emp[2].Salary = 35000; emp[2].Sex = 0;
                emp[3].FirstName = "Aarushi"; emp[3].LastName = "Shukla"; emp[3].Age = 25; emp[3].Salary = 20000; emp[3].Sex = 0;
                emp[4].FirstName = "Malini"; emp[4].LastName = "Kapoor"; emp[4].Age = 33; emp[4].Salary = 30000; emp[4].Sex = 1;

                Console.WriteLine("\nEmployee Array Before Call");
                for (int nI = 0; nI < nCnt; nI++)
                {
                    StringBuilder sb = new StringBuilder( "First Name=[" );
                    sb.Append(emp[nI].FirstName);
                    sb.Append("]  Last Name=[");
                    sb.Append(emp[nI].LastName );
                    sb.Append("]  Age=[");
                    sb.Append(emp[nI].Age .ToString ());
                    sb.Append("]  Salary=[");
                    sb.Append(emp[nI].Salary.ToString ("F2"));
                    sb.Append("]  Sex=[");
                    sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female"));
                    sb.Append("]");
                    Console.WriteLine(sb.ToString ());
                }

                // Call the Function.

                ModifyArrayOfEmployeeStruct(emp.Length, emp);

                Console.WriteLine("\nEmployee Array After Call");
                for (int nI = 0; nI < nCnt; nI++)
                {
                    StringBuilder sb = new StringBuilder("First Name=[");
                    sb.Append(emp[nI].FirstName);
                    sb.Append("]  Last Name=[");
                    sb.Append(emp[nI].LastName);
                    sb.Append("]  Age=[");
                    sb.Append(emp[nI].Age.ToString());
                    sb.Append("]  Salary=[");
                    sb.Append(emp[nI].Salary.ToString("F2"));
                    sb.Append("]  Sex=[");
                    sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female"));
                    sb.Append("]");
                    Console.WriteLine(sb.ToString());
                }

            }
        }
    }

    Point of Interest

  • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
  • DllImport defines the DLL entry point.

    compile and execute you will get following output.

    image

  • August 6, 2013 Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , , , | Leave a comment

    Modifying array of string values (default Marshaling)

    Define some functions in native dll (let say it “Win32Native.dll”)  as shown below. this function receives array of char pointers (string).

    extern "C" __declspec(dllexport) void ModifyStringArrayValues( int nCount, char* ppStrArray[] )

    Implementing Functions

    extern "C" __declspec(dllexport) void ModifyStringArrayValues( int nCount, char* ppStrArray[] )
    {
        size_t cchDest = 40;
        const size_t alloc_size = sizeof(char) * 40;
        for ( int nI = 0; nI < nCount; nI++ )
        {
            char *pszFormat = "<<from DLL>> [Modified String %2d]";
            STRSAFE_LPSTR temp = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size );
            StringCchPrintfA(temp, cchDest, pszFormat, nI);
            CoTaskMemFree( ppStrArray[nI] );
            ppStrArray[nI] = (char *) temp;
       }
    }

    Point of Interest

    • CoTaskMemAlloc is used to allocated the memory required.
    • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.
    • StringCchPrintfA printf used to print a formatted output to a string buffer.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
        class Program
        {
             [DllImport("Win32Native.dll")]
             public static extern double ModifyStringArrayValues(int nSize, [In, Out] String[] strArr);
        
            static void Main(string[] args)
            {
                int nSize = 5;
                string[] arrStr = new string[nSize];
                for (int nI = 0; nI < nSize; nI++) arrStr[nI] = "String " + (nI + 1).ToString();

               
                Console.WriteLine("String Values in Array, before calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1}", i, arrStr[i]));
                }

                ModifyStringArrayValues(nSize, arrStr);

                Console.WriteLine("String Values in Array, after calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1}", i, arrStr[i]));
                }
            }
        }
    }

    Point of Interest

    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.

    compile and execute you will get following output.

    image

    August 6, 2013 Posted by | .NET, CodeProject, Interoperability, Win32 | , , , , | Leave a comment

    Modifying array of numeric types (default Marshaling)

    Define some functions in native dll (let say it “Win32Native.dll”)  as shown below. These 2 functions receives integer buffer, and double buffer respectively.

    extern "C" __declspec(dllexport) int ModifyIntegerArrayValues ( int nSize, int* pArray)

    extern "C" __declspec(dllexport) double ModifyDoubleArrayValues ( int nSize, double* pArray)

    Implementing Functions

    extern "C" __declspec(dllexport) int ModifyIntegerArrayValues ( int nSize, int* pArray)
    {
        int nResult = 0 ;
        for ( int i = 0; i < nSize; i++ )
        {
            nResult += pArray[ i ];
            pArray[i] += 100;
        }
        return nResult;
    }

    extern "C" __declspec(dllexport) double ModifyDoubleArrayValues ( int nSize, double* pArray)
    {
        double dblResult = 0 ;
        for ( int i = 0; i < nSize; i++ )
        {
            dblResult += pArray[ i ];
            pArray[i] += 200 ;
        }
        return dblResult ;
    }

    Point of Interest

    • CoTaskMemAlloc is used to allocated the memory required.
    • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
        class Program
        {
             [DllImport("Win32Native.dll")]
            public static extern void ModifyIntegerArrayValues(int nCount, [In, Out] int[] arrStr);

             [DllImport("Win32Native.dll")]
             public static extern int ModifyDoubleArrayValues(int nSize, [In, Out] double[] nArr);
        
            static void Main(string[] args)
            {
                int nSize = 5 ;
                int[] arrInt = new int[nSize];
                for (int nI = 0; nI < nSize; nI++) arrInt[nI] = (nI + 1) * 10;

                Console.WriteLine("\nValues of Integer array, before calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1:D3}", i, arrInt[i]));
                }

                ModifyIntegerArrayValues(nSize, arrInt);

                Console.WriteLine("\nValues of Integer array, after calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1:D3}", i, arrInt[i]));
                }

                double [] arrDbl= new double [nSize];
                for (int nI = 0; nI < nSize; nI++) arrDbl[nI] = (nI + 1) * 5.0 ;

                Console.WriteLine("\nValues of Double array, before calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1:F2}", i, arrDbl[i]));
                }

                ModifyDoubleArrayValues(nSize, arrDbl);

                Console.WriteLine("\nValues of double array, after calling function");
                for (int i = 0; i < nSize; i++)
                {
                    Console.WriteLine(string.Format("Array[{0:D2}] : {1:F2}", i, arrDbl[i]));
                }
            }
        }
    }

    Point of Interest
    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.
    • Marshal.Copy function used to copy buffer from managed buffer to unmanaged buffer and vice versa.
    • Marshal.FreeCoTaskMem frees the memory allocated by native DLL.

    compile and execute you will get following output.

    image

    August 5, 2013 Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , , | Leave a comment

    Fetching an array of strings from a Win32 DLL

    Define  a function in native dll (let say it “Win32Native.dll”)  as shown below.

    extern "C" __declspec(dllexport) void FetchStringArray( int nCount, char* ppStrArray[])
    {
        int result = 0;
        STRSAFE_LPSTR temp;
        size_t cchDest = 40;

        const size_t alloc_size = sizeof(char) * 40;

        for ( int nI = 0; nI < nCount; nI++ )
        {
           char *pszFormat = "from DLL >> [returned String %d]";
           STRSAFE_LPSTR temp = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size );
           StringCchPrintfA(temp, cchDest, pszFormat, nI);

           CoTaskMemFree( ppStrArray[nI] );
           ppStrArray[nI] = (char *) temp;
        }
    }

    Point of Interest

    • CoTaskMemAlloc is used to allocated the memory required.
    • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

    Writing the client code (the managed part)

    one can simply create a console based application

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
       class Program
       {
           [DllImport("Win32Native.dll")]
           public static extern void FetchStringArray(int nCount, [In, Out] String[] arrStr);

           static void Main(string[] args)
           {
                int nSize = 10;
                String[] arrStr = new String[nSize];
                FetchStringArray(nSize, arrStr);
                Console.WriteLine("Returned String Array");
                for (int nI = 0; nI < nSize; nI++)
                {
                     Console.WriteLine(arrStr[nI]);
                }
           }

       }

    }

    Point of Interest

    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.

    compile and execute you will get following output.

    image

    August 4, 2013 Posted by | .NET, CodeProject, Interoperability, Win32 | , , , | Leave a comment

    Fetching buffer of numeric types from a Win32 DLL

    Define some functions in native dll (let say it “Win32Native.dll”)  as shown below. These 3 functions receives integer buffer, and double buffer respectively.

    extern "C" __declspec(dllexport) int FetchIntegerArray ( int nNewSize, int** ppnArray );

    extern "C" __declspec(dllexport) double  FetchDoubleArray ( int nNewSize, double ** ppnArray );

    Implementing Functions

    extern "C" __declspec(dllexport) int FetchIntegerArray ( int nNewSize, int** ppnArray )
    {
          int result = 0;
          //    CoTaskMemAlloc must be used because code on the managed side will call
          //    Marshal.FreeCoTaskMem to free this memory.
          int* newArray = (int*)CoTaskMemAlloc( sizeof(int) * nNewSize);
          for ( int j = 0; j < nNewSize ; j++ )
          {
               newArray[j] = ( j + 1 ) * 10 ;
               result += newArray[j];
           }

          if ( *ppnArray != NULL ) CoTaskMemFree( *ppnArray );
          *ppnArray = newArray;
          return result;
    }

    extern "C" __declspec(dllexport) double  FetchDoubleArray ( int nNewSize, double ** ppnArray )
    {
         double result = 0;
         //    CoTaskMemAlloc must be used because code on the managed side will call
         //    Marshal.FreeCoTaskMem to free this memory.
         double* newArray = (double*)CoTaskMemAlloc( sizeof(double) * nNewSize );
         for ( int j = 0; j < nNewSize ; j++ )
         {
             newArray[j] = 10 + ( j+1 ) * 30 ;
             result += newArray[j];
         }

         if ( *ppnArray != NULL ) CoTaskMemFree( *ppnArray );
         *ppnArray = newArray;
         return result;
    }

    Point of Interest

    • CoTaskMemAlloc is used to allocated the memory required.
    • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
       class Program
       {
           [DllImport("Win32Native.dll")]
           public static extern int FetchIntegerArray(int nSize, ref IntPtr arrInt);

           [DllImport("Win32Native.dll")]
           public static extern double FetchDoubleArray(int nSize, ref IntPtr arrInt);

           static void Main(string[] args)
           {
               int nSize = 10;
               IntPtr ptrArr = IntPtr.Zero;

               int nSum = FetchIntegerArray(nSize, ref ptrArr);
               int [] arrInt = new int [nSize];
               Marshal.Copy(ptrArr, arrInt, 0, nSize);

               Console.WriteLine("\nReturned Integer Buffer\n");

               for (int i = 0; i < nSize; i++)
               {
                   Console.Write("{0:}  ", arrInt[i]);
               }

               Console.Write("\nSum of Integer Buffer : {0}\n", nSum );
               Marshal.FreeCoTaskMem(ptrArr);

               ptrArr = IntPtr.Zero;
              double dblSum = FetchDoubleArray(nSize, ref ptrArr);
              double[] arrDbl = new double[nSize];
              Marshal.Copy(ptrArr, arrDbl, 0, nSize);

              Console.WriteLine("\nReturned Double Buffer\n");
              for (int i = 0; i < nSize; i++)
              {
                  Console.Write("{0:F2}  ", arrDbl[i]);
              }

              Console.Write("\nSum of Double Double Buffer : {0}\n", dblSum);
              Marshal.FreeCoTaskMem(ptrArr);
          }
       }
    }

    Point of Interest

    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.
    • Marshal.Copy function used to copy buffer from managed buffer to unmanaged buffer and vice versa.
    • Marshal.FreeCoTaskMem frees the memory allocated by native DLL.

    compile and execute you will get following output.

    image

    August 3, 2013 Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , , | Leave a comment

    Fetching a byte buffer from a Win32 DLL

     

    Define  a function in native dll (let say it “Win32Native.dll”)  as shown below.

    extern "C" __declspec(dllexport) int FetchByteArray ( int nSize, byte** ppnArray )
    {
        int result = 0;
        //    CoTaskMemAlloc must be used instead of the new operator because code on the managed side will call
        //    Marshal.FreeCoTaskMem to free this memory.
        byte* newArray = (byte*)CoTaskMemAlloc( sizeof(byte) * nSize );
        for ( int j = 0; j < nNewSize ; j++ )
        {
            newArray[j] = ( j+1 ) % 255 ;
            result += newArray[j];
        }

        // release the previous buffer, if any allocated.
        if ( *ppnArray != NULL ) CoTaskMemFree( *ppnArray );
        *ppnArray = newArray;
        return result;
    }

    Point of Interest
    • CoTaskMemAlloc is used to allocated the memory required.
    • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

    If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
        class Program
        {
            [DllImport("Win32Native.dll")]
            public static extern int FetchByteArray(int nSize, ref IntPtr arrInt);
        
            static void Main(string[] args)
            {
                int nSize = 10;
                IntPtr ptrArr = IntPtr.Zero;

                int nSum = FetchByteArray(nSize, ref ptrArr);
                byte[] arrByte = new byte[nSize];
                Marshal.Copy(ptrArr, arrByte, 0, nSize);

                Console.WriteLine("\nReturned Buffer\n");

                for (int i = 0; i < nSize; i++)
                {
                    Console.Write ( "{0:D2}  ", arrByte[i] );
                }
               
                Console.Write("\nSum of Buffer : {0}\n", nSum );
                Marshal.FreeCoTaskMem(ptrArr);
            }
        }
    }

    Point of Interest
    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.
    • Marshal.Copy function used to copy buffer from managed buffer to unmanaged buffer and vice versa.
    • Marshal.FreeCoTaskMem frees the memory allocated by native DLL.

    compile and execute you will get following output.

    image

    July 31, 2013 Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , , | Leave a comment

    Interoperability Returning a string from Wn32 DLL

    Define  a function in native dll (let say it “Win32Native.dll”)  as shown below.

    extern "C" __declspec(dllexport)  char * GetStringFromDLL()
    {
        const size_t alloc_size = 128;
        STRSAFE_LPSTR result=(STRSAFE_LPSTR)
    CoTaskMemAlloc(alloc_size);
        STRSAFE_LPCSTR teststr = "This is return string From Native DLL";
        StringCchCopyA ( result, alloc_size, teststr );
        return result;
    }

    Point of Interest

    • STRSAFE_LPSTR is a typedef of char *
    • StringCchCopy is a replacement for strcpy (with safety).  The size, in characters, of the destination buffer is provided to the function to ensure that StringCchCopyb does not write past the end of this buffer. has two variants.

    Writing the client code (the managed part)

    one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

    see the code snippet below.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Text;

    namespace MarshallingTest
    {
        class Program
        {
           [DllImport("Win32Native.dll")]
    public static extern String GetStringFromDLL();

            static void Main(string[] args)
            {
                Console.WriteLine("Line displayed below is returned from a Native DLL");
                string strData = GetStringFromDLL();
                Console.WriteLine ( "Returned value [" + strData +"]" );
            }
        }
    }

    Point of Interest

    • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
    • DllImport defines the DLL entry point.

    compile and execute you will get following output.

    image

     

    July 30, 2013 Posted by | CodeProject, Interoperability, Win32 | , , | Leave a comment

    Interoperability with Winodws API (1 of N)

    In this article I will explain, how one can call windows API, from managed world. let’s define the signatures of windows API for managed world.

    Calling a Win32 MessageBox function from Managed Word

    //****************************

    // MyProgram.cs

    namespace MyManagedProgram   {  //1

    class Program   { // 2
    static void Main(string[] args)   { //3

    Win32DllWrapper.MsgBox(0, "This Text has been sent from  Managed World",          "Win32 Messsage Box", 0);

    } //3

    }  //2

    ///defining the helper class

    ///define a helper class which will contain a functions for

    public class Win32DllWrapper   {    //4
    //  Standard Functions from Windows API.
    [DllImport("User32.dll", EntryPoint = "MessageBox", CharSet = CharSet.Auto)]
    public static extern int MsgBox(int hWnd, String text, String caption, uint type);

    }  //4

    }  // 1

    compile and execute

    July 26, 2013 Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , | Leave a comment