In windowsvista/win7/win8, we can use WSDAPI.dll to find/subscribe/unsubscribe the deviceand receive the events which sent out by devices actively(link),but winXP didn't have this dll, so we needimplement the function by ourselves. a good message is DPWSCore isdoing this work, it is a open source project with BSD license. So you canmodify her source and use the source in your product code.
Now the latest releaseversion of DPWSCore is 2.4.0.when you only want to only use the device's printevent, this version can meet your requirement. but this version doesn'tsupport the ScanDestinations in ScanAvailableEvent ,so if you want toscan print , you need to wait for release v3,this thread can explain this. we don't findthe v3 when this summer become a thing of past, so we need implement thisfunction by ourselves.
If you want the DPWScore handlethe ScanDestinations, you need add the related structure into subscribe message,subscribeResponse message for internal use, also need add relatedstructure for external use for configure the real destination.
Step 1:open the eventsource.gsoap and addthe ScanDestinations related structure into _wse__Subscribe ,addthe DestinationResponses related structureinto _wse__SubscribeResponse. the WSDSCAN.sln will generate thesefunctions according this gsoap file.
//gsoap sca schema namespace: http://schemas.microsoft.com/windows/2006/08/wdp/scan
//gsoap sca schema form: unqualified
typedef char* sca__ClientDisplayNameType;
typedef char* sca__ClientContextType;
struct sca__ScanDestinationType
{
sca__ClientDisplayNameType sca__ClientDisplayName 1;
sca__ClientContextType sca__ClientContext 1;
/// Extensible in the schema
};
struct sca__ScanDestinationsType
{
struct sca__ScanDestinationType *sca__ScanDestination 1;
};
struct _wse__Subscribe
{
endpoint_ref wse__EndTo 0;
struct wse__DeliveryType *wse__Delivery 1;
wse__ExpirationType wse__Expires 0;
struct wse__FilterType *wse__Filter 0;
struct sca__ScanDestinationsType *sca__ScanDestinations 0;
/// Extensible in the schema
};
struct sca__DestinationResponseType
{
sca__ClientContextType sca__ClientContext 1;
@xsd__anyURI sca__DestinationToken 1;
/// Extensible in the schema
};
struct sca__DestinationResponsesType
{
struct sca__DestinationResponseType *sca__DestinationResponse 1;
};
struct _wse__SubscribeResponse
{
endpoint_ref wse__SubscriptionManager 1;
wse__ExpirationType wse__Expires 1;
struct sca__DestinationResponsesType sca__DestinationResponses 0;
/// Extensible in the schema
};
Step 2: add wscn_scandestination_ref into dc_Types.hfor external use.
/**
* WS-Eventing ScanDestination reference
* Runtime structure that contains WS-Eventing ScanDestination reference data.
* Used for the source, reply to and fault to WSA header fields.
*/
struct sca_scandestination_ref {
char* client_display_name; /**< client display name */
char* client_context; /**< client context */
};
Step 3: add ScanDestinations ralted urlinto dcDPWS_Dpws.c/dc_Constants.h.
#define SCA_PREFIX "sca"
#define SCA_WILDCARD "http://schemas.xmlsoap.org/ws/*/eventing"
#define SCA_URI "http://schemas.microsoft.com/windows/2006/08/wdp/scan"
//add above macros into dpws11_default_namespaces,dpws10_protocols and dpws11_protocols in dcDPWS_Dpws.c. dpws10_eventing_snd_namespaces and dpws11_eventing_snd_namespaces in dcDPWS_Event.c.
Step 4: add ScanDestinationsType into dpws_event_subscribe_ex/dpws_event_subscribeas a parameter for external call in dc_Dpws.h and dcDPWS_Event.c.
//dc_Dpws.h
DC_RT_FMAC1 struct wsa_endpoint_ref * dpws_event_subscribe(struct dpws* dpws, struct wsa_endpoint_ref* event_source, struct wsa_endpoint_ref* notify_to, struct wsa_endpoint_ref* end_to, char ** filter, char ** expiration, struct sca_scandestination_ref *sca_destination);
DC_RT_FMAC1 struct wsa_endpoint_ref * dpws_event_subscribe_ex(struct dpws* dpws, struct wsa_endpoint_ref* event_source, short href_notify_to, short href_end_to, char ** filter, char ** expiration, struct sca_scandestination_ref *sca_destination);
//dcDPWS_Event.c.
struct wsa_endpoint_ref * dpws_event_subscribe_ex(
struct dpws* dpws,
struct wsa_endpoint_ref* event_source,
short href_notify_to,
short href_end_to,
char ** filter,
char ** expiration,
struct sca_scandestination_ref *scan_destination
)
{
struct wsa_endpoint_ref * sm;
http_transport_data_t * tdata;
char local_address[MAX_IP_ADDRESS_STRING_LEN];
struct wsa_endpoint_ref *notify_to = NULL, *end_to = NULL;
const transport_class_t * tclass;
DC_CHECK_PARAM_RETURN(dpws, NULL);
DC_CHECK_PARAM_NO_RC(dpws->err, event_source && href_notify_to >= 0 && expiration, NULL);
/* Connect to retrieve the local IP used for connecting the event source */
soap_set_endpoint(dpws_dpws2soap(dpws), event_source->address);
tclass = get_transport_class(event_source->address);
if (!tclass) {
dpws->err = WSA_ERR_DESTINATION_UNREACHABLE;
return NULL;
}
tdata = dc_http_open_output_channel(dpws, dpws->soap.host, (unsigned short)dpws->soap.port, tclass); // ports are positive integers
if (tdata == NULL)
return NULL;
if ((dpws->err = dc_http_get_local_address(dpws, tdata->base.socket, local_address, MAX_IP_ADDRESS_STRING_LEN)) != DPWS_OK)
goto error;
if (!(notify_to = (struct wsa_endpoint_ref *)DC_MSG_MALLOC(DC_MEM_API, dpws, sizeof(struct wsa_endpoint_ref))))
{
dpws->err = DPWS_ERR_EOM;
goto error;
}
if (!(notify_to = build_local_endpoint_ref(dpws, notify_to, local_address, href_notify_to)))
{
goto error;
}
if (href_end_to >= 0)
{
if (!(end_to = (struct wsa_endpoint_ref *)DC_MSG_MALLOC(DC_MEM_API, dpws, sizeof(struct wsa_endpoint_ref))))
{
dpws->err = DPWS_ERR_EOM;
goto error;
}
if (!(end_to = build_local_endpoint_ref(dpws, end_to, local_address, href_end_to)))
{
goto error;
}
}
sm = dpws_event_subscribe(dpws, event_source, notify_to, end_to, filter, expiration,scan_destination);
if ((dpws->err = dc_transport_close_channel(dpws)) != DPWS_OK)
return NULL;
return sm;
error:
dc_transport_close_channel(dpws);
return NULL;
}
struct wsa_endpoint_ref* dpws_event_subscribe(
struct dpws* dpws,
struct wsa_endpoint_ref* event_source,
struct wsa_endpoint_ref* notify_to,
struct wsa_endpoint_ref* end_to,
char ** filter,
char ** expiration,
struct sca_scandestination_ref *sca_destination
)
{
struct _wse__Subscribe subscription;
struct wse__DeliveryType delivery;
struct wse__FilterType s_filter;
struct _wse__SubscribeResponse response;
DA_TYPED(str) actions = DA_INITIALIZER(char *, DC_MEM_API, 2); // wrapper
struct wsa_endpoint_ref* ret = NULL;
int nbActions = 0;
DC_CHECK_PARAM_RETURN(dpws, NULL);
DC_CHECK_PARAM_NO_RC(dpws->err, event_source && notify_to && expiration, NULL);
soap_default__wse__Subscribe(dpws_dpws2soap(dpws), &subscription);
subscription.wse__EndTo = end_to;
subscription.wse__Delivery = &delivery;
delivery.Mode = WSE_MODE_PUSH;
delivery.wse__NotifyTo = notify_to;
#ifdef DC_WITH_WSMAN
delivery.wsman__Heartbeats = dpws->wsman_headers.heartbeats;
#else
delivery.wsman__Heartbeats = NULL;
#endif
subscription.wse__Expires = *expiration;
if (!filter || !*filter)
subscription.wse__Filter = NULL;
else {
subscription.wse__Filter = &s_filter;
s_filter.__item = (dyn_array_t *)&actions;
//s_filter.Dialect = event_source->dpws_version->wdp_wse_filtering_dialect;
s_filter.Dialect = DPWS10_WSE_FILTERING_DIALECT;
actions.tab = filter; // NOTE: custom uri list marshalling use the null boundary and not the nb field
while (*filter++) nbActions++;
actions.nb = nbActions;
}
if(sca_destination == NULL)
{
subscription.sca__ScanDestinations = NULL;
}else {
subscription.sca__ScanDestinations = (struct sca__ScanDestinationsType *)malloc(sizeof(struct sca__ScanDestinationsType));
subscription.sca__ScanDestinations->sca__ScanDestination = sca_destination;
}
if (dpws_call___wse__SubscribeOp(dpws, event_source, NULL, &subscription, &response))
goto exit;
*expiration = response.wse__Expires;
ret = response.wse__SubscriptionManager;
ret->dpws_version = dpws->protocols;
exit:
dpws_init_headers_and_version(dpws);
return ret;
}
One thing important is we just need ScanDestinations insubscribe ScanAvailableEvent ,not all of scan events.
Date Posted: October 12, 2012
Blog Posted: LCL_data at http://blog.csdn.net/lcl_data/article/details/8063426