0

An example MSR OPOS Service Object I am writing was not initializing properly. I am adding this question to help others who run into the same problem since various searches resulted in no help whatsoever.

My question is: How can I determine what method in an OPOS Service Object is missing? Is there a utility of some kind that can exercise an OPOS Service Object and tell me what is missing? Is there some way to determine what methods an interface is expected to provide and which are missing?

I am following the procedure in Writing an OPOS Service Object using ATL in order to learn how an OPOS Service Object is created. I am using Visual Studio 2005 under Windows XP. To test the basic functionality I am using the NCR Retail Services Manager (RSM) utility to create a profile for an MSR in order to test the basic functionality of a Mag Stripe Reader simulator Service Object.

The Visual Studio project creates the COM object and registers it properly. When I attempt to use the Diagnostics function of RSM on the Service Object profile I receive an error of OPOS_E_NOSERVICE. I have created a log file logging function in the COM object which shows that the Service Object is loaded, the DLLMain() function of the COM object is invoked and the DLLGetClassObject() is invoked. However a second log file which logs the various Service Object interface methods is not created indicating that none of the Service Object interface methods are called.

So it appears that there is a problem with the Service Object interface which fails a check that is done at the time the COM object is loaded.

The DllGetClassObject() function is generated by the Visual Studio ATL project wizard and should require no changes.

Using the Microsoft POS .NET sample utility which comes with POS .NET 1.12 I tried using the sample utility. I can see the profile created with NCR RSM in the tree control under the MSR node. However when I attempt an Open there is an error message. The Windows Event log shows the follow error.

Microsoft.PointOfService.PosControlException: Method Open threw an exception. The service object does not support one or more of the methods required by its release.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
  • Your post is going to end up being deleted if you don't do this the proper way. Ask a question, post an answer. – Hans Passant Jul 14 '15 at 15:05
  • @HansPassant, is that better? I did a google search on `OPOS_E_NOSERVICE` and this question appeared in the first page of results. If I had had this question two days ago, it would have helped me so I hope that it will help others. This seems to be a fairly esoteric area without a lot of documentation. – Richard Chambers Jul 14 '15 at 15:34

1 Answers1

0

I finally found the missing method from inspection and review of the code. It turns out that there was a single missing method, OpenService() which the Visual Studio 2005 ATL interface wizard had not created properly, possibly because it was the first method to be added to the interface for the Service Object.

When I attempted to add this method to the interface using the Visual Studio class wizard, the wizard issued an error message after I entered the method signature into the wizard dialog and pressed the Next button.

When retrying from scratch with a new ATL project, the error dialog had the following text:

Add/Remove operation is impossible, because the code element 'OpenServiceW' is read only.

While the method did show in the Visual Studio UI in the Class View when clicking on the method, the interface definition in the .idl file showed it as empty.

interface IVirtSo : IDispatch{
};

I closed Visual Studio then reopened the project and tried to add it again this time getting the error message:

Failed to return new Code Element. Possibly syntax error. New Element Name: OpenService

Further investigation indicates that there is an OpenService() method in the Windows API and it may be that Visual Studio 2005 ran into a conflict between my trying to add this method to my Service Object and it existing in the Windows API (actual name appears to be OpenServiceW()).

What I finally ended up doing was to add an interface method with the same signature, named CheckService() using the class wizard and then changed the interface method name everywhere it existed in my generated code to OpenService() including a couple of places where CheckService was part of a name or label. For some reason the Visual Studio class wizard thought the interface method of OpenService() existed when in fact it did not.

However before I was able to do this successfully, I had to first exit Visual Studio then delete the Intellisense files (.ncb file and .suo file) so that adding new methods using the Class View wizard would work properly. Before deleting the files, the id number of the Add -> Method in the wizard kept incrementing even with the method add failing. After deleting the Intellisense file the id number started at 1 again and I was able to add the CheckService() method with the wizard and then modify the method name to OpenService() by hand using the Find tool with "Match case" turned on and "Match whole word" turned off.

The only way that I can see thus far is to review the OPOS Service Object specification against the source code implementation of the Service Object.

I am looking for other possible solutions to finding methods are missing from an OPOS Service Object.

From the article and my current experience, it appears that the following are the common subset of methods that need to be available in an OPOS Service Object in order for the Service Object to load properly. Some of these are invoked only once as a part of starting up and initialing the Service Object. Others, such as GetPropertyNumber() and GetPropertyString() as well as the SET versions of these may be invoked multiple times as part of setting up the Service Object environment. There may be other entry points offered by a particular OPOS Common Controls object for a particular device type that would need to have a corresponding method in the Service Object.

HRESULT OpenService(BSTR DeviceClass, BSTR DeviceName, IDispatch* pDispatch, [out, retval] long* pRC);
HRESULT CheckHealth(long Level, [out, retval] long* pRC);
HRESULT ClaimDevice(long ClaimTimeout, [out, retval] long* pRC);
HRESULT ClearInput([out, retval] long* pRC);
HRESULT CloseService([out, retval] long* pRC);
HRESULT COFreezeEvents(VARIANT_BOOL Freeze, [out, retval] long* pRC);
HRESULT DirectIO(long Command, [in, out] long* pData, [in, out] BSTR* pString, [out, retval] long* pRC);
HRESULT ReleaseDevice([out, retval] long* pRC);

HRESULT GetPropertyNumber(long PropIndex, [out, retval] long* pNumber);
HRESULT GetPropertyString(long PropIndex, [out, retval] BSTR* pString);
HRESULT SetPropertyNumber(long PropIndex, long Number);
HRESULT SetPropertyString(long PropIndex, BSTR PropString);
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
  • 1
    All methods defined in the initial OPOS version (1.0) for a device class have to be there in your SO for it to open successfully. You can find methods and the version they initially appeared in the OPOS spec. When the open fails, use GetOpenResult method to get a descriptive error code. – dhanushka Jan 21 '16 at 15:56