$WINEPATH/tools/winebuild/winebuild -w --def -o libcount.def --export ./count.spec
|
»DLLs
|
Building Under WindowsThis final tutorial describes compiling the count service from the prior tutorials under Windows. This tutorial assumes that basic Windows development tools are installed and ready to use. a brief overview of installing this tool chain for Windows can be found in the notes about Visual Studio. Compilation of the count DLL or standalone count server can be accomplished by modifying the Makefiles provided in this tutorial. Synopsis
Source Code LayoutCopy the source code for this tutorial onto the Windows machine. Beware Windows uses custom version of libcount_proxy.def, count_private.h, and debug.h, rather than those available via Wine. Versions of these files customized for use in Windows are located in the count_tutorial/count_tutorial_for_windows/ directory of the tutorial source code.
Note that the libcount_proxy.def file is created from count_proxy.spec using the winebuild tool using the command: $WINEPATH/tools/winebuild/winebuild -w --def -o libcount.def --export ./count.spec A normal build creates this file for you. Manually update the def file for use under Windows by renaming the exports to have names without decoration. Wine generated version of libcount.def: ; File generated automatically from ./count_proxy.spec; do not edit! LIBRARY count_proxy.dll EXPORTS DllCanUnloadNow@0 @1 PRIVATE DllGetClassObject@12 @2 PRIVATE DllRegisterServer@0 @3 PRIVATE DllUnregisterServer@0 @4 PRIVATE GetProxyDllInfo@8 @5 should be modified placed in count_tutorial/dlls/count_proxy/libcount.def with the following updates: LIBRARY count_proxy.dll EXPORTS DllCanUnloadNow = _DllCanUnloadNow@0 PRIVATE DllGetClassObject = _DllGetClassObject@12 PRIVATE DllRegisterServer = _DllRegisterServer@0 PRIVATE DllUnregisterServer = _DllUnregisterServer@0 PRIVATE GetProxyDllInfo = _GetProxyDllInfo@8 A corrected copy of this file is available in src\count_tutorial_for_windows\libcount.def.
The count_private.h header uses the offsetof macro to locate vtable offsets within the CountImpl structure. Use of this macro in Windows requires the inclusion of the stddef.h header. Update count_private.h so that the first includes look like: #ifndef __COUNT_PRIVATE_H__ #define __COUNT_PRIVATE_H__ #include <stddef.h> #include <stdarg.h> #define COBJMACROS
Wine programs use macros such as WINE_DEBUG (internal to Wine) and DEBUG (general programs) to provide debugging and traces to developers. The following version of debug.h located at count_tutorial\count_tutorial_for_windows\debug.h should be copied into count_tutorial\include\wine\debug.h to provide null versions of these macros. Wine tests use the common header file test.h located at count_tutorial\count_tutorial_for_windows\test.h that must be copied into count_tutorial\include\wine\test.h to provide the testing marcos. Compiling the Count ProxyThe count_tutorial\count_tutorial_for_windows\Makefile.proxy should be manually copied into count_tutorial\count_proxy\Makefile. The count proxy DLL can then be built using nmake. Compiling the Count Proxy TestThe count_tutorial\count_tutorial_for_windows\Makefile.tests should be manually copied into count_tutorial\count_proxy\tests\Makefile. The count proxy DLL can then be built using nmake. Compiling the Count ServiceThe count_tutorial\count_tutorial_for_windows\Makefile.service should be manually copied into count_tutorial\count_proxy\programs\count_service\Makefile. The count proxy DLL can then be built using nmake. Extending the RegistryA few extra registry entries are needed to run the service through the SCM. The following registry entries can be added by hand using the Windows regedit program. Do be aware that editing the Windows registry can destroy your Windows installation. Edit at your own risk. REGEDIT4
[HKEY_CLASSES_ROOT\AppID\count_service]
"AppID"="{72f5782a-867e-11dc-8314-0800200c9a66}"
[HKEY_CLASSES_ROOT\AppID\{72f5782a-867e-11dc-8314-0800200c9a66}
"LocalService"="count_service"
[HKEY_CLASSES_ROOT\CLSID\{55E9B534-76AA-11DC-8B8E-F6CC56D89593}
"AppID"="{72f5782a-867e-11dc-8314-0800200c9a66}"
These entries can be added by executing regedit count.reg from the count_tutorial\count_tutorial_for_windows directory containing the above count_tutorial\count_tutorial_for_windows\count.reg file. Executing the Count Service
Potential Solutions to Common ProblemsDebugging output from a COM object running as a serviceMessage boxes provide a primitive printf form of debugging to trace the activity of a COM object exposed via a service. Easy and effective for simple tracing and examining error codes. Basic message box syntax is: char mb_text[200]; hres = ...; sprintf("Debugging text with printf var expansion: 0x%08X\n", hres); MessageBox(NULL, mb_string, NULL, MB_OK); The service must be configured to have access to interact with the desktop for this type of debugging. This is configurable via the by right clicking on the service in the Services utility, selecting the Log On tab, and checking the Allow service to interact with desktop box. Note that selecting this option can cause new sources of failure for your application. But its a start and has gotten me through some tough service startup bugs. Remember to remove the message boxes when you have finished debugging. Attempts to create an object by my client generates the error 0x80070005 (E_ACCESSDENIED)Need to properly configure the security settings of the service. These settings can be adjusted using calls to CoInitializeSecurity. A permissive setting to begin working from is: hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); You can also experiment with configuring the service to run as the current user. This is accomplished via the service name in the services utility, selecting Properties -> Log On -> This account, and specifying the current user account and password. Note that using CoInitializeSecurity is a better long term solution. Attempts to create an object by my client generates the error 0x800401F0 (CO_E_NOTINITIALIZED)This is a registry problem. Double check that the proxy / stub is registered and that the entries listed in "Extending the Registry" above are in the registry. Calling CoCreateInstance from client into COM object provided by a service hangsThe ServiceMain (or equivalent) function of your service is probably hanging do to improper handling of incoming messages. Either the call to CoInitialize must be declared as multithreaded or the ServiceMain needs to include a message handling loop rather than blocking for a stop event. A second source of hang is the use of message boxes when the service is not configured to interact with the desktop. Remember that (despite my advice above) services should generally not use message boxes. Attempts to start the service result in "Access Denied" errorsOne cause of this is incorrect folder / file permissions since services often run as "Local Service" rather than the user owning the service. Setting group read and execute permissions on folders / files in question may fix this problem. |