PROGHELP.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*****************************************************************************\
* PROGHELP.C
*
* Main module to implement a simple DDEML service DLL that makes interaction
* with progman simple.
\*****************************************************************************/

#include <windows.h>
#include <ddeml.h>
#include <string.h>

typedef struct {
HCONV hConv;
DWORD idInst;
} THREADINFO;

DWORD TlsIndex;

/*
* This is the default DDEML callback function for ProgHelp
*/
HDDEDATA CALLBACK ProgHelpDdeCallback(
UINT wType,
UINT wFmt,
HCONV hConv,
HSZ hsz1,
HSZ hsz2,
HDDEDATA hData,
DWORD dwData1,
DWORD dwData2)
{
return(0);
}


/*
* This is the DLL init routine called by the system at attach/detatch time.
*
* We allocate a Tls for each thread that calls this DLL so that their state
* can be tracked independently.
*/
BOOLEAN APIENTRY DllMain(
IN PVOID hmod,
ULONG Reason,
IN PCONTEXT pctx OPTIONAL)
{
THREADINFO *pti;
UNREFERENCED_PARAMETER(hmod);
UNREFERENCED_PARAMETER(pctx);

switch (Reason) {
case DLL_PROCESS_ATTACH:
TlsIndex = TlsAlloc();

case DLL_THREAD_ATTACH:
pti = (THREADINFO *)LocalAlloc(LPTR, sizeof(THREADINFO));
if (!pti) {
return(FALSE);
}
TlsSetValue(TlsIndex, pti);
break;

case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
pti = TlsGetValue(TlsIndex);
LocalFree(pti);
if (Reason == DLL_PROCESS_DETACH) {
TlsFree(TlsIndex);
}
break;
}
return TRUE;
}

/*
* An application must call this API first to establish a conversation
* with progman. DDEML initialization is done automatically if needed.
*/
BOOL ConnectToProgmanA()
{
THREADINFO *pti;
HSZ hszProgman;

pti = TlsGetValue(TlsIndex);

if (!pti->idInst) {
if (DdeInitializeA(&(pti->idInst), ProgHelpDdeCallback,
APPCMD_CLIENTONLY | CBF_SKIP_ALLNOTIFICATIONS,
0L) != DMLERR_NO_ERROR) {
return(FALSE);
}
}

if (pti->hConv == 0) {
hszProgman = DdeCreateStringHandleA(pti->idInst, "Progman", 0);
pti->hConv = DdeConnect(pti->idInst, hszProgman, hszProgman, NULL);
}
return(pti->hConv != 0);
}



BOOL ConnectToProgmanW()
{
THREADINFO *pti;
HSZ hszProgman;

pti = TlsGetValue(TlsIndex);

if (!pti->idInst) {
if (DdeInitializeW(&(pti->idInst), ProgHelpDdeCallback,
APPCMD_CLIENTONLY | CBF_SKIP_ALLNOTIFICATIONS,
0L) != DMLERR_NO_ERROR) {
return(FALSE);
}
}

if (pti->hConv == 0) {
hszProgman = DdeCreateStringHandleA(pti->idInst, "Progman", 0);
pti->hConv = DdeConnect(pti->idInst, hszProgman, hszProgman, NULL);
}
return(pti->hConv != 0);
}



/*
* This API should be called when operations with progman are complete.
* We shutdown DDEML here as well so we don't have to deal with it
* at DLL detatch time.
*/
BOOL DisconnectFromProgman()
{
THREADINFO *pti;

pti = TlsGetValue(TlsIndex);

if (!pti->idInst) {
return(TRUE);
}

if (pti->hConv) {
DdeDisconnect(pti->hConv);
pti->hConv = 0;
}

DdeUninitialize(pti->idInst);
pti->idInst = 0;
return(TRUE);
}


/*
* This API sends an ASCII execute string to progman. It immediately returns
* and the results of the execute are not known. Calling applications should
* be aware that these transactions are done asynchronously. This allows
* this API to work under modal-loop conditions. DisconnectFromProgman()
* will not succeed until all transactions are complete.
*/
BOOL ProgmanExecuteStringA(
LPSTR pszExec)
{
THREADINFO *pti;
DWORD dwResult;

pti = TlsGetValue(TlsIndex);

if (!pti->idInst || !pti->hConv) {
return(FALSE);
}
if (!DdeClientTransaction((PBYTE)pszExec, strlen(pszExec) + 1,
pti->hConv, 0, 0, XTYP_EXECUTE, TIMEOUT_ASYNC, &dwResult)) {
return(FALSE);
}
return(TRUE);
}



BOOL ProgmanExecuteStringW(
LPWSTR pszExec)
{
THREADINFO *pti;
DWORD dwResult;

pti = TlsGetValue(TlsIndex);

if (!pti->idInst || !pti->hConv) {
return(FALSE);
}
if (!DdeClientTransaction((PBYTE)pszExec,
(wcslen(pszExec) + 1) * sizeof(WCHAR),
pti->hConv, 0, 0, XTYP_EXECUTE, TIMEOUT_ASYNC, &dwResult)) {
return(FALSE);
}
return(TRUE);
}