LlmSendMessageEx Function  
 
BOOL WINAPI LlmSendMessageEx(
  HCLIENT hClient,  
  DWORD dwReserved,  
  LPLLM_MESSAGE lpMessage,  
  LPLLM_RESPONSE lpResponse  
);

The LlmSendMessageEx function sends a structured message to the model and returns a structured response.

Parameters

hClient
A handle to the client session.
dwReserved
A parameter reserved for future use. This value should always be zero.
lpMessage
A pointer to a LLM_MESSAGE structure which specifies the message to be sent to the server. This parameter cannot be NULL. The structure must be initialized correctly, with the dwSize member set to the size of the structure. Unused members of the structure should be initialized to zero or NULL.
lpResponse
A pointer to a LLM_RESPONSE structure which will be populated with information about the response from the server when the function returns. This parameter cannot be NULL. The structure must be initialized correctly, with the dwSize member set to the size of the structure and all other members set to a value of zero or NULL.

Return Value

If the function succeeds, the return value is non-zero. If the function fails, the return value is zero. To get extended error information, call LlmGetLastError.

Remarks

The LlmSendMessageEx function provides the structured form of LlmSendMessage. It should be used by applications that need to specify additional message properties, inspect detailed response metadata, or preserve information such as response identifiers, token usage, status values, elapsed time, and the actual model name returned by the provider.

This function performs a blocking operation. It will not return until the request has completed, an error has occurred, or the operation has timed out. Applications that call this function from a user interface thread should provide visual feedback while waiting for the response, or perform the request on a background thread to maintain responsiveness.

The lpMessage and lpResponse structures must be initialized before calling this function. At a minimum, the dwSize member of each structure must be set to the size of the structure, and all unused members should be initialized to zero or NULL.

If a message identifier is returned in the response structure, it is unique within the current client session. Message identifiers are assigned sequentially by the library, but applications should treat them as opaque values. They are not guaranteed to be globally unique across multiple sessions or between different clients.

This function automatically adds the message and response to the conversation history for the session. Subsequent calls may include previous messages as context, subject to any configured history or token limits. To clear the conversation context, call LlmClearHistory or LlmResetSession.

Applications that accept user input should apply appropriate validation, filtering, or normalization before sending requests to the service provider. The LlmValidateText function verifies that the prompt contains valid message text and the LlmNormalizeText function can be used to normalize text formatting. These functions do not perform any semantic analysis of the prompt and do not provide protection against malicious or intentionally misleading input.

Line breaks in the response text are normalized before being stored in the client history. Line feed and carriage return characters are converted to the standard Windows CRLF end-of-line sequence, ensuring consistent formatting across different providers and applications. This also helps ensure compatibility with Windows common controls and other user interface components.

Some models are capable of performing additional internal reasoning before generating a response. The amount of reasoning performed and whether it is exposed by the provider is model-specific. The library returns the final response intended for the user and does not currently expose model reasoning or intermediate processing steps. This behavior ensures consistent results across providers, regardless of how individual models implement or expose reasoning capabilities.

The string members of the LLM_MESSAGE and LLM_RESPONSE structures are managed by the library. When a message is sent, any string pointers provided in the LLM_MESSAGE structure are copied internally, and the application is not required to preserve or maintain those buffers after the function returns.

String pointers returned in the LLM_RESPONSE structure refer to memory managed by the client session. These values remain valid until the message history is cleared or the session is reset or disconnected. Applications should not attempt to free or modify these strings.

The contents of these strings must be treated as read-only. They are owned by the library, and modifying them may result in access violations or other undefined behavior. If your application needs to retain a string beyond the lifetime of the session or modify its contents, it should create its own copy.

Example

#include "cstools12.h"
#include <stdio.h>

int _tmain(void)
{
    HCLIENT hClient = INVALID_CLIENT;
    DWORD dwError = NO_ERROR;

    // Initialize the SocketTools library
    if (!LlmInitialize(CSTOOLS12_LICENSE_KEY, NULL))
    {
        _tprintf(_T("Initialization failed: %lu\n"), LlmGetLastError());
        return 1;
    }

    // Establish a connection to OpenAI using the default endpoint
    // and a lightweight model
    hClient = LlmConnect(
        LLM_PROVIDER_OPENAI,
        LLM_OPTION_DEFAULT,
        LLM_TIMEOUT,
        NULL,                   // Use default base URL
        _T("gpt-5.4-nano"),     // Model name
        _T("%OPENAI_API_KEY%")  // Provider API key
    );

    if (hClient == INVALID_CLIENT)
    {
        dwError = LlmGetLastError();
        _tprintf(_T("Unable to connect, error %lu\n"), dwError);
        LlmUninitialize();
        return 1;
    }

    LLM_MESSAGE clientMessage;
    ZeroMemory(&clientMessage, sizeof(LLM_MESSAGE));
    clientMessage.dwSize = sizeof(clientMessage);
    clientMessage.lpszContent = _T("What is the capital city of Denmark?");
    clientMessage.nContentLength = _tcslen(clientMessage.lpszContent);

    LLM_RESPONSE serverResponse;
    ZeroMemory(&serverResponse, sizeof(serverResponse));
    serverResponse.dwSize = sizeof(serverResponse);

    if (LlmSendMessageEx(hClient, 0, &clientMessage, &serverResponse))
    {
        _tprintf(_T("Flags: 0x%08lX\n"), serverResponse.dwFlags);
        _tprintf(_T("Status: %u\n"), serverResponse.dwStatus);
        _tprintf(_T("Elapsed: %u ms\n"), serverResponse.dwElapsed);
        _tprintf(_T("Output Tokens: %u\n"), serverResponse.nOutputTokens);
        _tprintf(_T("Content Length: %u\n"), serverResponse.nContentLength);
        _tprintf(_T("Response ID: %s\n"), (serverResponse.lpszResponseId ? serverResponse.lpszResponseId : _T("None")));
        _tprintf(_T("Model Name: %s\n"), (serverResponse.lpszModelName ? serverResponse.lpszModelName : _T("None")));
        _tprintf(_T("Status Text: %s\n"), (serverResponse.lpszStatusText ? serverResponse.lpszStatusText : _T("None")));

        if (serverResponse.nContentLength > 0)
            _tprintf(_T("\n%s\n"), serverResponse.lpszContent);
    }
    else
    {
        dwError = LlmGetLastError();
        _tprintf(_T("Request failed, error %lu\n"), dwError);
    }

    // Clean up
    LlmDisconnect(hClient);
    LlmUninitialize();

    return 0;
}

Requirements

Minimum Desktop Platform: Windows 7 Service Pack 1
Minimum Server Platform: Windows Server 2008 R2 Service Pack 1
Header File: cstools12.h
Import Library: csllmv12.lib
Unicode: Implemented as Unicode and ANSI versions

See Also

LlmClearHistory, LlmGetMessageById, LlmGetTokenUsage, LlmNormalizeText, LlmResetSession, LlmSendMessage, LlmValidateText, LLM_MESSAGE, LLM_RESPONSE