Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Nel mio post precedente abbiamo visto come scrivere un client C/C++ capace di invocare un servizio scritto in WCF.
In questo post vedremo come scrivere l’equivalente del servizio WCF in codice unmanaged tramite le WWSAPI.
A differenza della realizzazione di un client il server comporta ovviamente la scrittura a priori del WSDL e degli XSD !!! Questo perchè il linguaggio C/C++ non è così ricco di metadati come il framework .NET !! Quindi per gli amanti del contract-first nessun problema, mentre per i più pigri è sempre possibile definire l’interfaccia in WCF e quindi scaricare i metadati via svcutil /t:metadata :-) (come abbiamo fatto per il client)…
A questo punto possiamo avventurarci nella scrittura del nostro primo Web Service in C/C++
Creiamo un nuovo progetto di tipo Win32 Console Application.
Andiamo nella configurazione del progetto e selezioniamo All Configuration in alto a sinistra nella finestra di Property Page.
- Selezioniamo Configuration Properties->C/C++ –> Precompiled Headers e alla voce Create/Use Precompiled Header impostiamo : Not Using Precompiled Headers.
- Selezioniamo Configuration Properties->Linker->Input e alla voce Additional Dependencies scriviamo WebServices.lib.
Premiamo OK alla finestra di configurazione.
Includiamo i .h e .c presenti nella directory WSMetadata.
Aggiungiamo al progetto i files .h e .c presenti nella directory WSMetadata.
Aggiungiamo l’include ai file .h inseriti nel progetto e a <webservices.h>:
#include <webservices.h>#include "..\\wsmetadata\\mariofontanapublicdemos.com.CalculatorService.Bindings.wsdl.h"
#include "..\\wsmetadata\\mariofontanapublicdemos.com.CalculatorService.wsdl.h"
#include "..\\wsmetadata\\mariofontanapublicdemos.com.CalculatorService.xsd.h"
#include "..\\wsmetadata\\schemas.microsoft.com.2003.10.Serialization.xsd.h"Compiliamo…
Copiamo il codice riportato sotto e poi sempre animati da fiducia… compiliamo :-)
#include <iostream>
#include <conio.h>
// helper routine to print error object
void PrintError(HRESULT errorCode, WS_ERROR* error)
{
printf("Failure: errorCode=0x%lx\n", errorCode);
if (errorCode == E_INVALIDARG || errorCode == WS_E_INVALID_OPERATION)
{
// Correct use of the APIs should never generate these errors
printf("The error was due to an invalid use of an API. This is likely due to a bug in the program.\n");
//DebugBreak();
}
HRESULT hr = NOERROR;
if (error != NULL)
{
ULONG errorCount;
hr = WsGetErrorProperty(error, WS_ERROR_PROPERTY_STRING_COUNT, &errorCount, sizeof(errorCount));
if (FAILED(hr))
{
goto Exit;
}
for (ULONG i = 0; i < errorCount; i++)
{
WS_STRING string;
hr = WsGetErrorString(error, i, &string);
if (FAILED(hr))
{
goto Exit;
}
printf("%.*s\n", string.length, string.chars);
}
}
Exit:
if (FAILED(hr))
{
printf("Could not get error string (errorCode=0x%lx)\n", hr);
}
}
//questa è la vera e propria funzione callback che implementa il metodo Add
HRESULT CALLBACK Add(
__in const WS_OPERATION_CONTEXT* context,
__in int a,
__in int b,
__out __int64* result,
__in_opt const WS_ASYNC_CONTEXT* asyncContext,
__in_opt WS_ERROR* error)
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(asyncContext);
UNREFERENCED_PARAMETER(error);
*result = a + b;
printf ("%d + %d = %X\n", a, b, *result);
fflush(stdout);
return NOERROR;
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
WS_ERROR* error;
hr = WsCreateError(NULL,0, &error);
if (FAILED(hr)) return -1;
WS_HEAP* heap;
hr= WsCreateHeap(1024,0,NULL,0,&heap, error);
if(FAILED(hr))
{
WsFreeError(error);
return -1;
}
wprintf(L"Hosting del mio primo Web Service in C/C++...\n");
BasicHttpBinding_ICalculatorFunctionTable Functions = {Add};
WS_STRING url = WS_STRING_VALUE (L" https://localhost:8080/NativeCalculatorService");
WS_HTTP_BINDING_TEMPLATE templateValue = {};
WS_SERVICE_ENDPOINT* serviceEndpoint;
hr = BasicHttpBinding_ICalculator_CreateServiceEndpoint (&templateValue,url,&Functions,NULL,NULL,0,heap,&serviceEndpoint,error);
if(FAILED(hr))
{
PrintError(hr,error);
WsFreeHeap(heap);
WsFreeError(error);
return -1;
}
WS_SERVICE_HOST* host = NULL;
const WS_SERVICE_ENDPOINT* serviceEndpoints[1];
serviceEndpoints[0] = serviceEndpoint;
hr = WsCreateServiceHost(serviceEndpoints, 1,NULL, 0, &host, error);
if(FAILED(hr))
{
PrintError(hr,error);
WsFreeHeap(heap);
WsFreeError(error);
return -1;
}
hr = WsOpenServiceHost(host,NULL,error);
if(FAILED(hr))
{
PrintError(hr,error);
WsFreeServiceHost(host);
WsFreeHeap(heap);
WsFreeError(error);
return -1;
}
wprintf(L"Premi Enter per chiudere il servizio...\n");
_getch();
WsCloseServiceHost(host, NULL, error);
WsFreeServiceHost(host);
WsFreeHeap(heap);
WsFreeError(error);
return 0;
}
a questo punto Ctrl+F5 e lanciamo il nostro Web Service e torniamo sul codice client dove andremo a commentare il
#define _WCF
in modo da chiamare il Web Service che abbiamo appena creato. Come si può notare il codice client è il medesimo (salvo l’url) e possiamo invocare indistintamente Web Services scritti in WCF e in C/C++.
La schematizzazione del codice è la seguente :
--Mario
Comments
Anonymous
March 27, 2009
If you speak Italian, there are two great resources to learn more about connecting your native C/C++Anonymous
June 04, 2009
Sono appena tornato dal Delphi Day 2009, il secondo per me, dopo quello del 2007. Marco Cantù è stato