Skip to main content
Software used:
 
Microsoft Visual Studio Professional 2019
Version 16.11.42
 
Micro Focus Visual COBOL 8.0 
 
Operating System: Windows Server 2022 Datacenter
 
Problem Description:
 
We have few Micro Focus Visual COBOL program executables running as Windows services. These .cbl programs were created using 'Console Application, COBOL' option in Visual Studio editor. The built .exes were converted to services using NSSM (Non Sucking Service Manager). Requirement now is to eliminate NSSM and create core Visual COBOL code that runs itself as Windows services without help of any third party tool. Is this feasible with a project created with 'Console Application, COBOL' options?



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------
Software used:
 
Microsoft Visual Studio Professional 2019
Version 16.11.42
 
Micro Focus Visual COBOL 8.0 
 
Operating System: Windows Server 2022 Datacenter
 
Problem Description:
 
We have few Micro Focus Visual COBOL program executables running as Windows services. These .cbl programs were created using 'Console Application, COBOL' option in Visual Studio editor. The built .exes were converted to services using NSSM (Non Sucking Service Manager). Requirement now is to eliminate NSSM and create core Visual COBOL code that runs itself as Windows services without help of any third party tool. Is this feasible with a project created with 'Console Application, COBOL' options?



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Hi Kavitha,

We used to have a sample program in the old Net Express product that demonstrated how to create a Windows service using the native COBOL OO-support  and it was quite complex, but this is not available in Visual COBOL. In Visual COBOL there is a project template for creating a Windows Service using the .NET Framework that can be used instead.

I am attaching a small demo that I wrote by converting the C# tutorial found here to Visual COBOL.

I developed this using Visual COBOL V10 for Visual Studio 2022 so you probably cannot load it into your product version, but you could look at the source code used. If you need this instead using V8.0 and VS2019 let me know and I will try to create this for you.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Kavitha,

We used to have a sample program in the old Net Express product that demonstrated how to create a Windows service using the native COBOL OO-support  and it was quite complex, but this is not available in Visual COBOL. In Visual COBOL there is a project template for creating a Windows Service using the .NET Framework that can be used instead.

I am attaching a small demo that I wrote by converting the C# tutorial found here to Visual COBOL.

I developed this using Visual COBOL V10 for Visual Studio 2022 so you probably cannot load it into your product version, but you could look at the source code used. If you need this instead using V8.0 and VS2019 let me know and I will try to create this for you.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thank you so much for the response and the code. I tried the Windows Service (.NET Framework) project in Visual COBOL 8.0 and Visual Studio 2019. Included the code you had provided but facing few issues, trying to work through it. If you can provide the code for V8.0 and VS2019, it would be of great help. Thanks once again!

I believe installUtil.exe is the command to install this executable as service, can you please confirm?

------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------


Thank you so much for the response and the code. I tried the Windows Service (.NET Framework) project in Visual COBOL 8.0 and Visual Studio 2019. Included the code you had provided but facing few issues, trying to work through it. If you can provide the code for V8.0 and VS2019, it would be of great help. Thanks once again!

I believe installUtil.exe is the command to install this executable as service, can you please confirm?

------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Hi Chris!
Update on my previous message. I was able to get the basic Service program working with .NET Framework. I installed my program exe with InstallUtil and Service was installed and listed in Windows 'Services' application. Thanks much for your code.
 
I have a query on below call. I am trying to get the logged in Username through Visual COBOL code. Below code part worked fine in normal Visual VOBOL code: 
 
           call WINAPI "GetUserNameA" using by reference Buffer,
                                            by reference BufferLen
                                  returning aBool
           end-call
 
but when I include into Service program (MyNewService.cbl), compile, build went fine but when I start the service, I get an exception (below image). Also in Event Viewer, error is logged as given at the end of this message. I believe when service is started, it is not able to find 'GetUserNameA' program. While this worked fine in normal Visual COBOL, any workaround to get this working in Visual COBOL in .NET Framework?
 
Event Viewer Log:
- EventData 
 
   Service cannot be started. MicroFocus.COBOL.Program.COBOLProgramNotFound: 173 Called program file not found in drive/directory [GetUserNameA] at MicroFocus.COBOL.Program.Control.CallReturningObject
(UInt32 callConvention, String program, Object[] parameters, IObjectControl pgInstance) at MicroFocus.COBOL.Program.Control.Call(UInt32 callConvention, String program, Object[] parameters, IObjectControl 
pgInstance) at WindowsService5.Service1.OnStart(String[] args) in D:\\Kavitha\\WindowsService\\WindowsService5\\Service1.cbl:line 69 at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state) 

Thanks!



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------
Hi Chris!
Update on my previous message. I was able to get the basic Service program working with .NET Framework. I installed my program exe with InstallUtil and Service was installed and listed in Windows 'Services' application. Thanks much for your code.
 
I have a query on below call. I am trying to get the logged in Username through Visual COBOL code. Below code part worked fine in normal Visual VOBOL code: 
 
           call WINAPI "GetUserNameA" using by reference Buffer,
                                            by reference BufferLen
                                  returning aBool
           end-call
 
but when I include into Service program (MyNewService.cbl), compile, build went fine but when I start the service, I get an exception (below image). Also in Event Viewer, error is logged as given at the end of this message. I believe when service is started, it is not able to find 'GetUserNameA' program. While this worked fine in normal Visual COBOL, any workaround to get this working in Visual COBOL in .NET Framework?
 
Event Viewer Log:
- EventData 
 
   Service cannot be started. MicroFocus.COBOL.Program.COBOLProgramNotFound: 173 Called program file not found in drive/directory [GetUserNameA] at MicroFocus.COBOL.Program.Control.CallReturningObject
(UInt32 callConvention, String program, Object[] parameters, IObjectControl pgInstance) at MicroFocus.COBOL.Program.Control.Call(UInt32 callConvention, String program, Object[] parameters, IObjectControl 
pgInstance) at WindowsService5.Service1.OnStart(String[] args) in D:\\Kavitha\\WindowsService\\WindowsService5\\Service1.cbl:line 69 at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state) 

Thanks!



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Here is a sample of getting the user name 3 ways in a .NET program:

      $set ilusing"System.Runtime.InteropServices"
       class-id. myclass as "testNETwinapi.myclass".
       method-id Main public static.
       procedure division.

           *> 1. Use platform invoke
           declare user-name as type StringBuilder = new StringBuilder(256)
           declare user-len as binary-long = 256
           declare mybool = GetUserNameA(by value user-name, by reference user-len)

           *> 2. Get logged in user
           declare user-name2 as string = type Environment::UserName

           *> 3. Get Domain also
           declare user-name3 as string = type System.Security.Principal.WindowsIdentity::GetCurrent::Name
           goback.
       
       end method.
       method-id GetUserNameA static private
       attribute DllImport("advapi32.dll").
       procedure division using by value user-name as type StringBuilder
                                         reference user-len as binary-long
                           returning mybool as condition-value.
       
       end method.
       end class myclass.


------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Here is a sample of getting the user name 3 ways in a .NET program:

      $set ilusing"System.Runtime.InteropServices"
       class-id. myclass as "testNETwinapi.myclass".
       method-id Main public static.
       procedure division.

           *> 1. Use platform invoke
           declare user-name as type StringBuilder = new StringBuilder(256)
           declare user-len as binary-long = 256
           declare mybool = GetUserNameA(by value user-name, by reference user-len)

           *> 2. Get logged in user
           declare user-name2 as string = type Environment::UserName

           *> 3. Get Domain also
           declare user-name3 as string = type System.Security.Principal.WindowsIdentity::GetCurrent::Name
           goback.
       
       end method.
       method-id GetUserNameA static private
       attribute DllImport("advapi32.dll").
       procedure division using by value user-name as type StringBuilder
                                         reference user-len as binary-long
                           returning mybool as condition-value.
       
       end method.
       end class myclass.


------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Actually, the way that you are doing it in native code can also be done in managed code. You just have to add the following directive to the top of the program:

$set ilpinvoke"advapi32.dll"



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Actually, the way that you are doing it in native code can also be done in managed code. You just have to add the following directive to the top of the program:

$set ilpinvoke"advapi32.dll"



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------
Hi Chris,
 
Thank you so much for the response.
 
$set ilpinvoke"advapi32.dll"
Yes addition of above statement made the Call WINAPI work. I will have to include more Call WINAPI functions in my future code, hoping all work as expected.
 
I have been trying to write my own messages into event log. For example, below statement in your code, I expected it to write message "In Start." into the event log which can be seen in Event Viewer
           invoke eventLog1::WriteEntry("In Start.")
 
but only the Windows related service message appears and none of the WriteEntry function messages make to Event Viewer logs. Am I missing something here?


------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------
Hi Chris,
 
Thank you so much for the response.
 
$set ilpinvoke"advapi32.dll"
Yes addition of above statement made the Call WINAPI work. I will have to include more Call WINAPI functions in my future code, hoping all work as expected.
 
I have been trying to write my own messages into event log. For example, below statement in your code, I expected it to write message "In Start." into the event log which can be seen in Event Viewer
           invoke eventLog1::WriteEntry("In Start.")
 
but only the Windows related service message appears and none of the WriteEntry function messages make to Event Viewer logs. Am I missing something here?


------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

The same program that I gave to you works correctly on my system and all messages are written to the event log.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

The same program that I gave to you works correctly on my system and all messages are written to the event log.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thanks Chris.

I might be installing or running services different way - After exe build, I do 
1) install using InstallUtil command through command prompt
2) To run the service, I go to services panel, start/stop my service in the list
 
Is this the right way to install and invoke our built exe service program?


------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Thanks Chris.

I might be installing or running services different way - After exe build, I do 
1) install using InstallUtil command through command prompt
2) To run the service, I go to services panel, start/stop my service in the list
 
Is this the right way to install and invoke our built exe service program?


------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Under which user account are you running the service?

The tutorial has the following warning:

--------------------------

This setting installs the service and runs it by using the local system account.

 Important

The LocalSystem account has broad permissions, including the ability to write to the event log. Use this account with caution, because it might increase your risk of attacks from malicious software. For other tasks, consider using the LocalService account, which acts as a non-privileged user on the local computer and presents anonymous credentials to any remote server. This example fails if you try to use the LocalService account, because it needs permission to write to the event log.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Under which user account are you running the service?

The tutorial has the following warning:

--------------------------

This setting installs the service and runs it by using the local system account.

 Important

The LocalSystem account has broad permissions, including the ability to write to the event log. Use this account with caution, because it might increase your risk of attacks from malicious software. For other tasks, consider using the LocalService account, which acts as a non-privileged user on the local computer and presents anonymous credentials to any remote server. This example fails if you try to use the LocalService account, because it needs permission to write to the event log.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Chris,

I believe I am logged in as LocalSystem account as I was able to write to event log using the code attached. Attached code is a pure Visual COBOL code (not Windows service program) when run using start command wrote the instructed messages to event log which was verified in the Event Viewer. But if I use the same Call WINAPI ReportEventA or WriteEntry() function in Windows service program, specified logs in the code do not reflect in Event Viewer.

Do you suspect that event log writing through a Windows service program (that is run by starting the service manually) might require a different kind of user permission as against the event log write using the pure Visual COBOL code (that is run by start command in command line) ?



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Hi Chris,

I believe I am logged in as LocalSystem account as I was able to write to event log using the code attached. Attached code is a pure Visual COBOL code (not Windows service program) when run using start command wrote the instructed messages to event log which was verified in the Event Viewer. But if I use the same Call WINAPI ReportEventA or WriteEntry() function in Windows service program, specified logs in the code do not reflect in Event Viewer.

Do you suspect that event log writing through a Windows service program (that is run by starting the service manually) might require a different kind of user permission as against the event log write using the pure Visual COBOL code (that is run by start command in command line) ?



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

When you are not running as a service the program will be run with the credentials of the logged in user by default.

When run as a service you can select the account under which the service will be run. Bring up the Services window where you are starting the service, and the Log On As field will show you what this is.

In this tutorial there is the following section that details setting the account to LocalSystem so that it will have the proper rights to write to the registry.

--------

In the Design view for ProjectInstaller, choose serviceProcessInstaller1 for a C# project, or ServiceProcessInstaller1 for a Visual Basic project, then choose Properties from the shortcut menu. Set the Account property to LocalSystem from the drop-down list.

This setting installs the service and runs it by using the local system account.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

When you are not running as a service the program will be run with the credentials of the logged in user by default.

When run as a service you can select the account under which the service will be run. Bring up the Services window where you are starting the service, and the Log On As field will show you what this is.

In this tutorial there is the following section that details setting the account to LocalSystem so that it will have the proper rights to write to the registry.

--------

In the Design view for ProjectInstaller, choose serviceProcessInstaller1 for a C# project, or ServiceProcessInstaller1 for a Visual Basic project, then choose Properties from the shortcut menu. Set the Account property to LocalSystem from the drop-down list.

This setting installs the service and runs it by using the local system account.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thank you for your guidance, Chris. My service program was writing to event logs with both User and LocalSystem account. I missed to check the right place where program logs were written. Until now, I was checking only 'Application' under 'Windows Logs' in Event Viewer. Only after going through each item thoroughly, I found that the program written logs appear under 'Applications and Service Logs'. I believe I got the basic service program functioning with user enabled event logging. I will proceed to add more functionality to this structure as my project develops.

I had query on below code. I believe SetServiceStatus method and below timer related statements are optional and are not a necessity for event log write functionality. Can you please confirm? 

      method-id SetServiceStatus private static
          attribute DllImport("advapi32.dll").
      procedure division using handle as type System.IntPtr,
                               by reference serviceStatus as type ServiceStatus
                     returning mybool as condition-value.

      end method.


          declare timer = new type Timer
          set timer::Interval = 60000 *> 60 seconds
          attach new type ElapsedEventHandler(self::OnTimer) to timer::Elapsed
          invoke timer::Start
          declare serviceStatus = new type ServiceStatus
          set serviceStatus::dwCurrentState = type ServiceState::SERVICE_START_PENDING
          set serviceStatus::dwWaitHint = 100000
          declare mybool as condition-value
            = type Service1::SetServiceStatus(self::ServiceHandle, by reference serviceStatus)
          set serviceStatus::dwCurrentState = type ServiceState::SERVICE_RUNNING
          set mybool = type Service1::SetServiceStatus(self::ServiceHandle, by reference serviceStatus)



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Thank you for your guidance, Chris. My service program was writing to event logs with both User and LocalSystem account. I missed to check the right place where program logs were written. Until now, I was checking only 'Application' under 'Windows Logs' in Event Viewer. Only after going through each item thoroughly, I found that the program written logs appear under 'Applications and Service Logs'. I believe I got the basic service program functioning with user enabled event logging. I will proceed to add more functionality to this structure as my project develops.

I had query on below code. I believe SetServiceStatus method and below timer related statements are optional and are not a necessity for event log write functionality. Can you please confirm? 

      method-id SetServiceStatus private static
          attribute DllImport("advapi32.dll").
      procedure division using handle as type System.IntPtr,
                               by reference serviceStatus as type ServiceStatus
                     returning mybool as condition-value.

      end method.


          declare timer = new type Timer
          set timer::Interval = 60000 *> 60 seconds
          attach new type ElapsedEventHandler(self::OnTimer) to timer::Elapsed
          invoke timer::Start
          declare serviceStatus = new type ServiceStatus
          set serviceStatus::dwCurrentState = type ServiceState::SERVICE_START_PENDING
          set serviceStatus::dwWaitHint = 100000
          declare mybool as condition-value
            = type Service1::SetServiceStatus(self::ServiceHandle, by reference serviceStatus)
          set serviceStatus::dwCurrentState = type ServiceState::SERVICE_RUNNING
          set mybool = type Service1::SetServiceStatus(self::ServiceHandle, by reference serviceStatus)



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Hi Kavitha,

That's great that you are up and running!

Yes, you are correct that the SetServiceStatus function code is optional and is just included in the example, for the sake of completeness. It is however recommended that if your service takes a long time starting up or shutting down that it is a good idea to set the SERVICE_START_PENDING and SERVICE_STOP_PENDING statuses so that the user is informed as to what is going on. The timer routine is simply to emulate a long startup process for the example.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Kavitha,

That's great that you are up and running!

Yes, you are correct that the SetServiceStatus function code is optional and is just included in the example, for the sake of completeness. It is however recommended that if your service takes a long time starting up or shutting down that it is a good idea to set the SERVICE_START_PENDING and SERVICE_STOP_PENDING statuses so that the user is informed as to what is going on. The timer routine is simply to emulate a long startup process for the example.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thank you Chris for that clear explanation.

I have been progressing on including more project related code to the service program. When I began including a bit more complex logic into the program, build is giving below error:

error COBCH1501 : Insufficient memory

It is the same code logic which I tested standalone and worked good, but when included in service program, gives above build error. Do you have suggestions to overcome this build error?

Thanks!



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Thank you Chris for that clear explanation.

I have been progressing on including more project related code to the service program. When I began including a bit more complex logic into the program, build is giving below error:

error COBCH1501 : Insufficient memory

It is the same code logic which I tested standalone and worked good, but when included in service program, gives above build error. Do you have suggestions to overcome this build error?

Thanks!



------------------------------
Kavitha Natarajan
Rocket Software Forum Member
------------------------------

Hi Kavitha,

I suggest opening a support case to report the issue you are encountering during build. You may do so via https://my.rocketsoftware.com or by contacting your local Rocket Software customer care (see https://my.rocketsoftware.com/RocketCommunity/s/contact-us" target="_blank" rel="noopener">Contact Us).

 Regards,



------------------------------
Fano R.
Developer/Engineer
Rocket Forum Shared Account
------------------------------

Hi Kavitha,

That's great that you are up and running!

Yes, you are correct that the SetServiceStatus function code is optional and is just included in the example, for the sake of completeness. It is however recommended that if your service takes a long time starting up or shutting down that it is a good idea to set the SERVICE_START_PENDING and SERVICE_STOP_PENDING statuses so that the user is informed as to what is going on. The timer routine is simply to emulate a long startup process for the example.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Chris,

Fano has been helping me with the build error. Meanwhile, I had a clarification while including more COBOL logic with tags in columns 73 to 80. This works fine in a standalone COBOL application. However, when the same logic is included inside the service program, compile error is thrown for each statement that have tags in 73rd column. Sample error is shown in below picture. Is there a workaround for such compile error?



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------


Hi Chris,

Fano has been helping me with the build error. Meanwhile, I had a clarification while including more COBOL logic with tags in columns 73 to 80. This works fine in a standalone COBOL application. However, when the same logic is included inside the service program, compile error is thrown for each statement that have tags in 73rd column. Sample error is shown in below picture. Is there a workaround for such compile error?



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

Hi Kavitha,

The default sourceformat directive for native COBOL projects in Visual Studio is Fixed Format in which Area B stops at column 72 but for managed .NET projects (which is what you are now using), the default is Variable Format, in which Area B is extended to 250 characters. You are getting the error because the compiler assumes that these comments are part of the source code and not comments as they would be in Fixed Format.

To solve this problem you can change the sourceformat directive to Fixed Format on the COBOL tab of the Project Properties page or you could make your comments in-line comments by prefacing them with an *> 

e.g.         *> tag 1



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Kavitha,

The default sourceformat directive for native COBOL projects in Visual Studio is Fixed Format in which Area B stops at column 72 but for managed .NET projects (which is what you are now using), the default is Variable Format, in which Area B is extended to 250 characters. You are getting the error because the compiler assumes that these comments are part of the source code and not comments as they would be in Fixed Format.

To solve this problem you can change the sourceformat directive to Fixed Format on the COBOL tab of the Project Properties page or you could make your comments in-line comments by prefacing them with an *> 

e.g.         *> tag 1



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thank you Chris! Project properties change to Fixed has resolved the compiler issue. Currently, I have a query on this - I am including a logic that calls standalone native COBOL program - ProgramA (say) that is already compiled, built and .exe is present in a different location other than /bin/debug. Is there anyway that our service program will be able to pick this .dll or .exe from this location (other than /bin/debug) when a CALL statement is included?



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

Thank you Chris! Project properties change to Fixed has resolved the compiler issue. Currently, I have a query on this - I am including a logic that calls standalone native COBOL program - ProgramA (say) that is already compiled, built and .exe is present in a different location other than /bin/debug. Is there anyway that our service program will be able to pick this .dll or .exe from this location (other than /bin/debug) when a CALL statement is included?



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

In order to call a native program from a managed application the native program would have to be a .dll, not an .exe.
If you set the system PATH to include the folder in which the native .dll resides it will be searched during the call.

You could also set the path in an app.config file that you add to your managed project that could look like the following:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!--The following code declares a section group for application configuration -->
    <sectionGroup name="MicroFocus.COBOL.Application">
      <section name="Switches" type="System.Configuration.NameValueSectionHandler" />
      <section name="Environment" type="System.Configuration.NameValueSectionHandler" />
    </sectionGroup>
    <!--The following code declares a section group for run-time configuration -->
    <sectionGroup name="MicroFocus.COBOL.Runtime">
      <section name="Tunables" type="System.Configuration.NameValueSectionHandler" />
      <section name="Switches" type="System.Configuration.NameValueSectionHandler" />
    </sectionGroup>
  
  </configSections>
<MicroFocus.COBOL.Application>
<Switches></Switches>
<Environment>
<add key="PATH" value="C:\\tests\\testpathNET\\subprog\\bin\\x64\\Debug;%PATH%" />
</Environment>
</MicroFocus.COBOL.Application>
</configuration>


------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

In order to call a native program from a managed application the native program would have to be a .dll, not an .exe.
If you set the system PATH to include the folder in which the native .dll resides it will be searched during the call.

You could also set the path in an app.config file that you add to your managed project that could look like the following:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!--The following code declares a section group for application configuration -->
    <sectionGroup name="MicroFocus.COBOL.Application">
      <section name="Switches" type="System.Configuration.NameValueSectionHandler" />
      <section name="Environment" type="System.Configuration.NameValueSectionHandler" />
    </sectionGroup>
    <!--The following code declares a section group for run-time configuration -->
    <sectionGroup name="MicroFocus.COBOL.Runtime">
      <section name="Tunables" type="System.Configuration.NameValueSectionHandler" />
      <section name="Switches" type="System.Configuration.NameValueSectionHandler" />
    </sectionGroup>
  
  </configSections>
<MicroFocus.COBOL.Application>
<Switches></Switches>
<Environment>
<add key="PATH" value="C:\\tests\\testpathNET\\subprog\\bin\\x64\\Debug;%PATH%" />
</Environment>
</MicroFocus.COBOL.Application>
</configuration>


------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Chris,

Thank you for the response. I have been doing changes and test runs myself to see if I can overcome 'Insufficient memory' build issue that I have been facing. So far, no luck.

This is my program scenario - In my .cbl program of the Windows service program, I have a copybook which calls two programs - A, B. Programs A, B are .dlls which are already compiled and built. Programs A, B source .cbl and their corresponding .dlls are present in a different location other than the Windows service project. Now, when I build my Windows service program, I get 'Insufficient memory' error. If I add the programs A, B to my Windows service project and compile, build, build completes without error. I want to understand why this is so. Please let me know your thoughts on this.

Additional location info - 

Windows service project source location - D:\\Kavitha\\WindowsService\\WindowsService8
Windows service project .exe location - D:\\Kavitha\\WindowsService\\WindowsService8\\bin\\Debug
Program A,B source location - D:\\VCSOURCE
Program A,B .dll location - D:\\VCRUN

Thanks & Regards,
Kavitha.



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

Hi Chris,

Thank you for the response. I have been doing changes and test runs myself to see if I can overcome 'Insufficient memory' build issue that I have been facing. So far, no luck.

This is my program scenario - In my .cbl program of the Windows service program, I have a copybook which calls two programs - A, B. Programs A, B are .dlls which are already compiled and built. Programs A, B source .cbl and their corresponding .dlls are present in a different location other than the Windows service project. Now, when I build my Windows service program, I get 'Insufficient memory' error. If I add the programs A, B to my Windows service project and compile, build, build completes without error. I want to understand why this is so. Please let me know your thoughts on this.

Additional location info - 

Windows service project source location - D:\\Kavitha\\WindowsService\\WindowsService8
Windows service project .exe location - D:\\Kavitha\\WindowsService\\WindowsService8\\bin\\Debug
Program A,B source location - D:\\VCSOURCE
Program A,B .dll location - D:\\VCRUN

Thanks & Regards,
Kavitha.



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

Hi Kavitha,

We tested this yesterday with the example that you sent in through the support case and we discovered what is causing the memory error during compilation. It appears to be a combination of using the ilpinvoke"advapi32.dll" and the call to "GETVARS". It appears to be trying to resolve the reference to the call "GETVARS" within the native .dll. If I change the name of GETVARS to something else the error doesn't occur.

I find that if you comment out the ilpinvoke directive and instead add a reference to your project by right-clicking on the references folder and project name and selecting Add Reference and then using the Browse button to navigate and select c:\\Windows\\system32\\advapi32.dll then the compiler error goes away.

We are still investigating but if you could give this a try and see if it fixes the issue for you, that would be helpful.

Thanks.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Hi Kavitha,

We tested this yesterday with the example that you sent in through the support case and we discovered what is causing the memory error during compilation. It appears to be a combination of using the ilpinvoke"advapi32.dll" and the call to "GETVARS". It appears to be trying to resolve the reference to the call "GETVARS" within the native .dll. If I change the name of GETVARS to something else the error doesn't occur.

I find that if you comment out the ilpinvoke directive and instead add a reference to your project by right-clicking on the references folder and project name and selecting Add Reference and then using the Browse button to navigate and select c:\\Windows\\system32\\advapi32.dll then the compiler error goes away.

We are still investigating but if you could give this a try and see if it fixes the issue for you, that would be helpful.

Thanks.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------
Thank you Chris! Yes, your later suggestion (comment out the ilpinvoke directive and instead add a reference to your project by right-clicking on the references folder and project name and selecting Add Reference and then using the Browse button to navigate and select c:\\Windows\\system32\\advapi32.dll) did help in getting a clean compile and build! I will keep this commented, reference added code and proceed with rest of the development.
--
I had query on ACCEPT statement. Most ACCEPT statements got compiled without error. However, when below kind of ACCEPT statement is included, compiler error is thrown.
--
statement:
ACCEPT ACCEPT-CHAR
                  AT LINE   CURSOR-ROW
                     COLUMN CURSOR-COLUMN
                  WITH TIMEOUT AFTER 5.
Compile error:



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------


Thank you Chris! Yes, your later suggestion (comment out the ilpinvoke directive and instead add a reference to your project by right-clicking on the references folder and project name and selecting Add Reference and then using the Browse button to navigate and select c:\\Windows\\system32\\advapi32.dll) did help in getting a clean compile and build! I will keep this commented, reference added code and proceed with rest of the development.
--
I had query on ACCEPT statement. Most ACCEPT statements got compiled without error. However, when below kind of ACCEPT statement is included, compiler error is thrown.
--
statement:
ACCEPT ACCEPT-CHAR
                  AT LINE   CURSOR-ROW
                     COLUMN CURSOR-COLUMN
                  WITH TIMEOUT AFTER 5.
Compile error:



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

Actually, you shouldn't have any console screen I-O in a Windows Service as, by default they run in the background without any user interaction.

You can get rid of the error by changing the output type to Console Application on the Application project properties tab.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Actually, you shouldn't have any console screen I-O in a Windows Service as, by default they run in the background without any user interaction.

You can get rid of the error by changing the output type to Console Application on the Application project properties tab.



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------

Thank you Chris. Yes, in the present requirement outcome, there is no console operation to be done. These code/subprograms I have been working on to include have been developed more than 15+ years. ACCEPT/DISPLAY and few more console related statements are present. Unfortunately, budget/time constraint to alter all of them now.

I was hesitant in the beginning to change the Output type in properties to Console application thinking if the windows service execution will be affected in anyway. I tested with a basic service program and the change in properties worked good with service execution too.

Now, with present code that I have shared in the support case, compile and build came out clean, but facing below error during service start.

----



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------


Thank you Chris. Yes, in the present requirement outcome, there is no console operation to be done. These code/subprograms I have been working on to include have been developed more than 15+ years. ACCEPT/DISPLAY and few more console related statements are present. Unfortunately, budget/time constraint to alter all of them now.

I was hesitant in the beginning to change the Output type in properties to Console application thinking if the windows service execution will be affected in anyway. I tested with a basic service program and the change in properties worked good with service execution too.

Now, with present code that I have shared in the support case, compile and build came out clean, but facing below error during service start.

----



------------------------------
Kavitha Natarajan
Fidelity Information Svcs Inc
------------------------------

On the project properties Application tab, change the Startup object to be Main:



------------------------------
Chris Glazier
Principal Technical Support Specialist
Rocket Forum Shared Account
------------------------------