News:

Download Pelles C here: http://www.smorgasbordet.com/pellesc/

Main Menu

Recent posts

#11
Work in progress / Re: Task Schedule 2.0 examples
Last post by John Z - December 09, 2025, 09:39:39 PM
Agree for Unix, I used cron for many things.  However the windows Task Scheduler interactive GUI is very easy to use and access.  Programmatically it is a bit harder.

Here is a powershell script creator in C to schedule a task...
typedef struct names{
  char AppPath[MAX_PATH];
  char VBSTime[50];
  char VBETime[50];
  char TaskName[50];
  char UserSTime[50];
  char Message[50];
}names;

names name;

/****************************************************************************
 *                                                                          *
 * Function: Create_Script_PS1                                              *
 *                                                                          *
 * Purpose : create runnable Powershell script for task                     *
 *                                                                          *
 * History : Date      Reason                                               *
 *           01/31/25  Created   John Z                                     *
 *                                                                          *
 * Globals :SYSTEMTIME dpst, SYSTEMTIME dpet;                               *
 ****************************************************************************/
void Create_Script_PS1(void)
{   int RetVal; 
char FileName [MAX_PATH*2]={0};
FILE *p_file;
    char buf2[4000]={0};
    char *p_buf2;

p_buf2 = buf2;  //wide char


    strcpy(FileName,name.AppPath);
strcat(FileName,"scr1.ps1");

p_file = fopen(FileName,"wb+"); //For Binary Access Write
    if (p_file == NULL)
      {
snprintf(buf2,MAX_PATH*2,"Unable to open file.\r\nFilename: %s",FileName);
MessageBoxA( NULL, buf2, "File Access Error",
MB_OK | MB_ICONERROR | MB_TOPMOST);
return;
  }

    snprintf(p_buf2, 3999,"%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A",
             "$TriggerTypeTime = 1",
             "$ActionTypeExec = 0",
             "$service = New-Object -ComObject Schedule.Service",
             "$service.Connect()"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);


    snprintf(p_buf2, 3999,"%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A",
             "$rootFolder = $service.GetFolder(\"\\\")",
             "$taskDefinition = $service.NewTask(0)",
             "$taskDefinition.RegistrationInfo.Description = \"Start Alert at a certain time\""
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);
          fflush(p_file);

    snprintf(p_buf2, 3999,"%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A",
             "$taskDefinition.RegistrationInfo.Author = \"CalendarZ\"",
             "$taskDefinition.Principal.LogonType = 3",
             "$taskDefinition.Settings.Enabled = $true",
             "$taskDefinition.Settings.StartWhenAvailable = $true"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);


    snprintf(p_buf2, 3999,"%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A",
             "$taskDefinition.Settings.Hidden = $false",
             "$taskDefinition.Settings.DeleteExpiredTaskAfter = \"PT10M\"",
             "$triggers = $taskDefinition.Triggers",
             "$trigger = $triggers.Create($TriggerTypeTime)"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);
          fflush(p_file);

   snprintf(p_buf2, 3999,"%s'%s'\x0D\x0A%s'%s'\x0D\x0A%s\x0D\x0A%s\x0D\x0A",
             "$startTime = ",name.VBSTime,
             "$endTime = ",name.VBETime,
             "$trigger.StartBoundary = $startTime",
             "$trigger.EndBoundary = $endTime"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);
          fflush(p_file);
   snprintf(p_buf2, 3999,"%s\x0D\x0A%s\x0D\x0A%s\"%s%s\"\x0D\x0A",
             "$actions = $taskDefinition.Actions",
             "$action = $actions.Create($ActionTypeExec)",
             "$action.Path = ",
              name.AppPath,
         "Alert.exe"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);

   snprintf(p_buf2, 3999,"%s%s -%s\"\x0D\x0A",
             "$Action.Arguments = \"-",
          name.UserSTime,
          name.Message
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);

    snprintf(p_buf2, 3999,"%s\x0D\x0A%s,\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A%s\x0D\x0A)",
             "$rootFolder.RegisterTaskDefinition(",
         name.TaskName,
             "    $taskDefinition,",
             "    6, # Task creation flag (6 = CREATE_OR_UPDATE)",
             "    $null, # User",
         "    $null, # Password",
             "    $null, # Logon type",
             "    $null # SDDL"
             );
    RetVal = fwrite(p_buf2, sizeof(char), strlen(p_buf2), p_file);
          fflush(p_file);

    fclose(p_file);
//MessageBox(NULL,"Completed!","Create Alert",MB_OK);


}/* end create_script_ps1 */

Not too bad, I have one for VBS too if interested...
I would have preferred in C but couldn't quite manage, so I'll learn from Timo's effort.

John Z
#12
Work in progress / Re: Task Schedule 2.0 examples
Last post by Vortex - December 09, 2025, 09:18:57 PM
The cron jobs of UNIX\Linux are much more simple to maintain.
#13
Work in progress / Re: Task Schedule 2.0 examples
Last post by MrBcx - December 09, 2025, 04:53:36 PM
Quote from: Vortex on December 09, 2025, 11:26:23 AMAdditionaly, MrBcx created some useful applications too :

https://bcxbasiccoders.com/smf/index.php?topic=1443.0

To get at my code, one mostly needs to be a registered user and logged in.

Here is a list of my most recent uploads:

* Communicate with an AI Server using COM
* COM Demos For Using Windows Task Scheduler Services
* Send a JSON record via WinHttp
* Fetch a JSON record via WinHttp
* REST API toolkit in BCX
 
Only the BCX BASIC source code is provided for each. 
If you want the Pelles C compatible code, you'll need to use the BCX Translator.
#14
Expert questions / Re: PellesC_V13\Include\Win\oc...
Last post by TimoVJL - December 09, 2025, 03:33:59 PM
A that ocidl.h don't have usual safe guard for windows.h and ole2.h
Perhaps have a good reason for that.
#15
Expert questions / Re: PellesC_V13\Include\Win\oc...
Last post by Vortex - December 09, 2025, 01:54:36 PM
Sometimes, it's better to copy the confusing equates from the net and paste them to the source file. In this case, you have to omit the header file.
#16
Work in progress / Re: Task Schedule 2.0
Last post by TimoVJL - December 09, 2025, 12:56:10 PM
I just converted a MS code example from C++ to C.

TaskCreate2.c
This needs some fixing.
/********************************************************************
 This sample schedules a task to start on a daily basis.
********************************************************************/
#define WIN32_LEAN_AND_MEAN
#define _WIN32_DCOM

#include <windows.h>
//#include <iostream>
#include <stdio.h>
//#include <comdef.h>
#include <wincred.h>
//  Include the task header file.
#include <taskschd.h>
#pragma comment(lib, "taskschd.lib")
//#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "credui.lib")

//using namespace std;

int __cdecl wmain(void)
{
    //  ------------------------------------------------------
    //  Initialize COM.
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        printf("\nCoInitializeEx failed: %x", hr );
        return 1;
    }

    //  Set general COM security levels.
    hr = CoInitializeSecurity(
        NULL,
        -1,
        NULL,
        NULL,
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
        RPC_C_IMP_LEVEL_IMPERSONATE,
        NULL,
        0,
        NULL);

    if( FAILED(hr) )
    {
        printf("\nCoInitializeSecurity failed: %x", hr );
        CoUninitialize();
        return 1;
    }

    //  ------------------------------------------------------
    //  Create a name for the task.
    LPCWSTR wszTaskName = L"Daily Trigger Test Task";

    //  Get the windows directory and set the path to notepad.exe.
    LPCWSTR wstrExecutablePath = _wgetenv( L"WINDIR");
    //wstrExecutablePath += L"\\SYSTEM32\\NOTEPAD.EXE";

   

    //  ------------------------------------------------------
    //  Create an instance of the Task Service.
    ITaskService *pService = NULL;
    hr = CoCreateInstance( &CLSID_TaskScheduler,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           &IID_ITaskService,
                           (void**)&pService ); 
    if (FAILED(hr))
    {
        printf("Failed to create an instance of ITaskService: %x", hr);
        CoUninitialize();
        return 1;
    }
    VARIANT v1, v2, v3, v4;
VariantInit(&v1);
VariantInit(&v2);
VariantInit(&v3);
VariantInit(&v4);
 
    //  Connect to the task service.
    //hr = pService->Connect(_variant_t(), _variant_t(), _variant_t(), _variant_t());
hr = pService->lpVtbl->Connect(pService, v1, v2, v3, v4);
    if( FAILED(hr) )
    {
        printf("ITaskService::Connect failed: %x", hr );
        pService->lpVtbl->Release(pService);
        CoUninitialize();
        return 1;
    }

    //  ------------------------------------------------------
    //  Get the pointer to the root task folder.  This folder will hold the
    //  new task that is registered.
    ITaskFolder *pRootFolder = NULL;
    hr = pService->lpVtbl->GetFolder(pService, L"\\" , &pRootFolder );
    if( FAILED(hr) )
    {
        printf("Cannot get Root Folder pointer: %x", hr );
        pService->lpVtbl->Release(pService);
        CoUninitialize();
        return 1;
    }
   
    // If the same task exists, remove it.
    pRootFolder->lpVtbl->DeleteTask(pRootFolder, (wchar_t*)wszTaskName, 0  );
   
    //  Create the task builder object to create the task.
    ITaskDefinition *pTask = NULL;
    hr = pService->lpVtbl->NewTask(pService, 0, &pTask );
   
    pService->lpVtbl->Release(pService);  // COM clean up.  Pointer is no longer used.
    if (FAILED(hr))
    {
        printf("Failed to CoCreate an instance of the TaskService class: %x", hr);
        pRootFolder->lpVtbl->Release(pRootFolder);
        CoUninitialize();
        return 1;
    }
           
    //  ------------------------------------------------------
    //  Get the registration info for setting the identification.
    IRegistrationInfo *pRegInfo= NULL;
    hr = pTask->lpVtbl->get_RegistrationInfo(pTask, &pRegInfo );
    if( FAILED(hr) )
    {
        printf("\nCannot get identification pointer: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();       
        return 1;
    }
   
    hr = pRegInfo->lpVtbl->put_Author(pRegInfo, L"Author Name" );
    pRegInfo->lpVtbl->Release(pRegInfo);  // COM clean up.  Pointer is no longer used.
    if( FAILED(hr) )
    {
        printf("\nCannot put identification info: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }
   
    //  ------------------------------------------------------
    //  Get the trigger collection to insert the daily trigger.
    ITriggerCollection *pTriggerCollection = NULL;
    hr = pTask->lpVtbl->get_Triggers(pTask, &pTriggerCollection );
    if( FAILED(hr) )
    {
        printf("\nCannot get trigger collection: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }
       
    //  Add the daily trigger to the task.
    ITrigger *pTrigger = NULL;   
    hr = pTriggerCollection->lpVtbl->Create(pTriggerCollection, TASK_TRIGGER_DAILY, &pTrigger );
    pTriggerCollection->lpVtbl->Release(pTriggerCollection);
    if( FAILED(hr) )
    {
        printf("\nCannot create the trigger: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }     
   
    IDailyTrigger *pDailyTrigger = NULL;
    hr = pTrigger->lpVtbl->QueryInterface(pTrigger,
        &IID_IDailyTrigger, (void**) &pDailyTrigger );
    pTrigger->lpVtbl->Release(pTrigger);
    if( FAILED(hr) )
    {
        printf("\nQueryInterface call on IDailyTrigger failed: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }
   
    hr = pDailyTrigger->lpVtbl->put_Id(pDailyTrigger, L"Trigger1" );
    if( FAILED(hr) )
        printf("\nCannot put trigger ID: %x", hr);

    //  Set the task to start daily at a certain time. The time
    //  format should be YYYY-MM-DDTHH:MM:SS(+-)(timezone).
    //  For example, the start boundary below
    //  is January 1st 2005 at 12:05
    hr = pDailyTrigger->lpVtbl->put_StartBoundary(pDailyTrigger, L"2005-01-01T12:05:00" );
    if( FAILED(hr) )
        printf("\nCannot put start boundary: %x", hr);
   
    //  Set the time when the trigger is deactivated.
    hr = pDailyTrigger->lpVtbl->put_EndBoundary(pDailyTrigger, L"2007-05-02T12:05:00" );
    if( FAILED(hr) )
        printf("\nCannot put the end boundary: %x", hr);
 
    //  Define the interval for the daily trigger. An interval of 2 produces an
    //  every other day schedule
    hr = pDailyTrigger->lpVtbl->put_DaysInterval(pDailyTrigger, (short)2 );
    if( FAILED(hr) )
    {
        printf("\nCannot put days interval: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pDailyTrigger->lpVtbl->Release(pDailyTrigger);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }

    // Add a repetition to the trigger so that it repeats
    // five times.
    IRepetitionPattern *pRepetitionPattern = NULL;
    hr = pDailyTrigger->lpVtbl->get_Repetition(pDailyTrigger, &pRepetitionPattern );
    pDailyTrigger->lpVtbl->Release(pDailyTrigger);
    if( FAILED(hr) )
    {
        printf("\nCannot get repetition pattern: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }
   
    hr = pRepetitionPattern->lpVtbl->put_Duration(pRepetitionPattern, L"PT4M");
    if( FAILED(hr) )
    {
        printf("\nCannot put repetition duration: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pRepetitionPattern->lpVtbl->Release(pRepetitionPattern);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }

    hr = pRepetitionPattern->lpVtbl->put_Interval(pRepetitionPattern, L"PT1M");
    pRepetitionPattern->lpVtbl->Release(pRepetitionPattern);
    if( FAILED(hr) )
    {
        printf("\nCannot put repetition interval: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }   
 

    //  ------------------------------------------------------
    //  Add an action to the task. This task will execute notepad.exe.     
    IActionCollection *pActionCollection = NULL;

    //  Get the task action collection pointer.
    hr = pTask->lpVtbl->get_Actions(pTask, &pActionCollection );
    if( FAILED(hr) )
    {
        printf("\nCannot get task collection pointer: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }
       
    //  Create the action, specifying that it is an executable action.
    IAction *pAction = NULL;
    hr = pActionCollection->lpVtbl->Create(pActionCollection, TASK_ACTION_EXEC, &pAction );
    pActionCollection->lpVtbl->Release(pActionCollection);
    if( FAILED(hr) )
    {
        printf("\nCannot create action: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }

    IExecAction *pExecAction = NULL;
    hr = pAction->lpVtbl->QueryInterface(pAction,
        &IID_IExecAction, (void**) &pExecAction );
    pAction->lpVtbl->Release(pAction);
    if( FAILED(hr) )
    {
        printf("\nQueryInterface call failed for IExecAction: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }

    //  Set the path of the executable to notepad.exe.
    hr = pExecAction->lpVtbl->put_Path(pExecAction, (wchar_t *)wstrExecutablePath );
    pExecAction->lpVtbl->Release(pExecAction);
    if( FAILED(hr) )
    {
        printf("\nCannot put the executable path: %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        return 1;
    }

    //  ------------------------------------------------------
    //  Securely get the user name and password. The task will
    //  be created to run with the credentials from the supplied
    //  user name and password.
    CREDUI_INFOW cui;
    WCHAR pszName[CREDUI_MAX_USERNAME_LENGTH] = L"";
    WCHAR pszPwd[CREDUI_MAX_PASSWORD_LENGTH] = L"";
    BOOL fSave;
    DWORD dwErr;

    cui.cbSize = sizeof(CREDUI_INFO);
    cui.hwndParent = NULL;
    //  Ensure that MessageText and CaptionText identify
    //  what credentials to use and which application requires them.
    cui.pszMessageText = L"Account information for task registration:";
    cui.pszCaptionText = L"Enter Account Information for Task Registration";
    cui.hbmBanner = NULL;
    fSave = FALSE;

    //  Create the UI asking for the credentials.
    dwErr = CredUIPromptForCredentialsW(
        &cui,                             //  CREDUI_INFO structure
        L"",                         //  Target for credentials
        NULL,                             //  Reserved
        0,                                //  Reason
        pszName,                          //  User name
        CREDUI_MAX_USERNAME_LENGTH,       //  Max number for user name
        pszPwd,                           //  Password
        CREDUI_MAX_PASSWORD_LENGTH,       //  Max number for password
        &fSave,                           //  State of save check box
        CREDUI_FLAGS_GENERIC_CREDENTIALS |  //  Flags
        CREDUI_FLAGS_ALWAYS_SHOW_UI |
        CREDUI_FLAGS_DO_NOT_PERSIST); 

    if(dwErr)
    {
        printf("Did not get credentials.\n");
        CoUninitialize();
        return 1;     
    }
   
    //  ------------------------------------------------------
    //  Save the task in the root folder.
VariantInit(&v1);
VariantInit(&v2);
VariantInit(&v3);
v1.vt = VT_BSTR;
v1.bstrVal = SysAllocString(pszName);
v2.vt = VT_BSTR;
v2.bstrVal = SysAllocString(pszPwd);

    IRegisteredTask *pRegisteredTask = NULL;
    hr = pRootFolder->lpVtbl->RegisterTaskDefinition(pRootFolder,
            (wchar_t *)wszTaskName,
            pTask,
            TASK_CREATE_OR_UPDATE,
            v1, //_variant_t(_bstr_t(pszName)),
            v2, //_variant_t(_bstr_t(pszPwd)),
            TASK_LOGON_PASSWORD,
            v3, //_variant_t(L""),
            &pRegisteredTask);
    if( FAILED(hr) )
    {
        printf("\nError saving the Task : %x", hr );
        pRootFolder->lpVtbl->Release(pRootFolder);
        pTask->lpVtbl->Release(pTask);
        CoUninitialize();
        SecureZeroMemory(pszName, sizeof(pszName));
        SecureZeroMemory(pszPwd, sizeof(pszPwd));
        return 1;
    }

    printf("\n Success! Task successfully registered. " );

    //  Clean up
    pRootFolder->lpVtbl->Release(pRootFolder);
    pTask->lpVtbl->Release(pTask);
    pRegisteredTask->lpVtbl->Release(pRegisteredTask);
    CoUninitialize();
    SecureZeroMemory(pszName, sizeof(pszName));
    SecureZeroMemory(pszPwd, sizeof(pszPwd));
    return 0;
}
#17
Work in progress / Re: Task Schedule 2.0
Last post by Vortex - December 09, 2025, 11:26:23 AM
Timo's work is nice. Additionaly, MrBcx created some useful applications too :

https://bcxbasiccoders.com/smf/index.php?topic=1443.0
#18
Work in progress / Re: Task Schedule 2.0
Last post by John Z - December 09, 2025, 11:21:21 AM
Timo - wow,

This is very interesting work. When I get through some other things I'll grab it.

In the past I've used vbs and ps scripts to enable applications to set schedules.  Your work might lead to using straight C to do the same thing.


John Z
#19
Expert questions / Re: PellesC_V13\Include\Win\oc...
Last post by John Z - December 09, 2025, 11:17:39 AM
Interesting -


What I found is that it appears that in Pelles V13 objbase.h is a mandatory prerequisite for using ocidl.h.

I added ocidl.h to the zsizer demo program and it failed compile with the same error messages.  Following Timo's example program I added objbase.h before ocidl.h and it compiles just fine, no errors

Change the order and put objbase.h after ocidl.h and it again fails with all of the error messages.

In Pelles V12 this is NOT the case, ocidl.h could be referenced alone. 

The two versions of ocidl.h are substantially different, but both insert needed additional .h files.
IMO if ocidl.h fails miserably without objbase.h being referenced first, shouldn't ocidl.h first check if objbase.h has been referenced and if not #include it at the start?

In any case thanks Timo for the example it showed a method to a fix.

John Z
#20
Work in progress / Re: Task Schedule 2.0
Last post by Vortex - December 09, 2025, 11:11:15 AM
Hi Timo,

Thanks, the application works fine on Windows 11 2024 H2.