414 lines
12 KiB
C
414 lines
12 KiB
C
/****************************** Module Header ******************************\
|
|
* Module Name: ddemlcli.c
|
|
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
* DDE Manager main client side module
|
|
|
|
* Created: 10/3/91 Sanford Staab
|
|
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
// DDEML globals
|
|
|
|
PCL_INSTANCE_INFO pciiList = NULL;
|
|
RTL_CRITICAL_SECTION gcsDDEML;
|
|
#if DBG
|
|
PVOID gpDDEMLHeap;
|
|
#endif
|
|
|
|
/*
|
|
* Description:
|
|
* Used two different ways:
|
|
* 1) First time call (*pidInst == 0) - causes a DDEML instance to be created for the calling process/thread. Creates a server side
|
|
* event window, server side instance structure, DDE Access Object, and client side instance structure.
|
|
* The callback function address and filter flags (afCmd) are placed into these structures.
|
|
* 2) Subsequent call (*pidInst == hInst) - updates filter flags in client and server side structures.
|
|
|
|
* History:
|
|
* 11-1-91 sanfords Created.
|
|
*/
|
|
UINT DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd, DWORD ulRes)
|
|
{
|
|
if (ulRes != 0) {
|
|
return (DMLERR_INVALIDPARAMETER);
|
|
}
|
|
|
|
return (InternalDdeInitialize(pidInst, pfnCallback, afCmd, 0));
|
|
}
|
|
|
|
|
|
UINT DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd, DWORD ulRes)
|
|
{
|
|
if (ulRes != 0) {
|
|
return (DMLERR_INVALIDPARAMETER);
|
|
}
|
|
|
|
return (InternalDdeInitialize(pidInst, pfnCallback, afCmd, 1));
|
|
}
|
|
|
|
|
|
UINT InternalDdeInitialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd, BOOL fUnicode)
|
|
{
|
|
UINT uiRet = DMLERR_MEMORY_ERROR;
|
|
register PCL_INSTANCE_INFO pcii;
|
|
|
|
if (afCmd & APPCLASS_MONITOR) {
|
|
afCmd |= CBF_MONMASK;
|
|
}
|
|
|
|
if (afCmd & APPCMD_CLIENTONLY) {
|
|
afCmd |= CBF_FAIL_CONNECTIONS;
|
|
}
|
|
|
|
EnterDDECrit;
|
|
|
|
if (*pidInst != 0) {
|
|
pcii = ValidateInstance((HANDLE)LongToHandle( *pidInst ));
|
|
if (pcii == NULL) {
|
|
uiRet = DMLERR_INVALIDPARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
// only allow certain bits to be changed on reinitialize call
|
|
|
|
pcii->afCmd = (pcii->afCmd & ~(CBF_MASK | MF_MASK)) | (afCmd & (CBF_MASK | MF_MASK));
|
|
|
|
LeaveDDECrit;
|
|
NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, afCmd);
|
|
return (DMLERR_NO_ERROR);
|
|
}
|
|
|
|
pcii = (PCL_INSTANCE_INFO)DDEMLAlloc(sizeof(CL_INSTANCE_INFO));
|
|
if (pcii == NULL) {
|
|
uiRet = DMLERR_MEMORY_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
pcii->plaNameService = (LATOM *)DDEMLAlloc(sizeof(LATOM));
|
|
if (pcii->plaNameService == NULL) {
|
|
uiRet = DMLERR_MEMORY_ERROR;
|
|
goto Backout3;
|
|
}
|
|
// *pcii->plaNameService = 0; // zero init takes care of this
|
|
pcii->cNameServiceAlloc = 1;
|
|
|
|
/*
|
|
* Flag this window as being create from a diff hmod as the app so hotkeys don't take it as the first window created in the app and assign it as the hotkey.
|
|
*/
|
|
pcii->hwndMother = _CreateWindowEx(0, (LPTSTR)(gpsi->atomSysClass[ICLS_DDEMLMOTHER]), L"", WS_POPUP, 0, 0, 0, 0, (HWND)0, (HMENU)0, 0, (LPVOID)NULL, CW_FLAGS_DIFFHMOD);
|
|
if (pcii->hwndMother == 0) {
|
|
uiRet = DMLERR_SYS_ERROR;
|
|
goto Backout2;
|
|
}
|
|
SetWindowLongPtr(pcii->hwndMother, GWLP_INSTANCE_INFO, (LONG_PTR)pcii);
|
|
|
|
pcii->afCmd = afCmd | APPCMD_FILTERINITS;
|
|
pcii->pfnCallback = pfnCallback;
|
|
// pcii->LastError = DMLERR_NO_ERROR; // zero init
|
|
pcii->tid = GetCurrentThreadId();
|
|
// pcii->aServerLookup = NULL; // zero init
|
|
// pcii->cServerLookupAlloc = 0; // zero init
|
|
// pcii->ConvStartupState = 0; // zero init - Not blocked.
|
|
// pcii->flags = 0; // zero init
|
|
// pcii->cInDDEMLCallback = 0; // zero init
|
|
// pcii->pLinkCounts = NULL; // zero init
|
|
|
|
// Do this last when the client side is ready for whatever events
|
|
// flying around may come charging in.
|
|
|
|
LeaveDDECrit;
|
|
uiRet = NtUserDdeInitialize(&pcii->hInstServer, &pcii->hwndEvent, &pcii->MonitorFlags, pcii->afCmd, pcii);
|
|
EnterDDECrit;
|
|
|
|
if (uiRet != DMLERR_NO_ERROR) {
|
|
Backout:
|
|
NtUserDestroyWindow(pcii->hwndMother);
|
|
Backout2:
|
|
DDEMLFree(pcii->plaNameService);
|
|
Backout3:
|
|
DDEMLFree(pcii);
|
|
goto Exit;
|
|
}
|
|
pcii->hInstClient = AddInstance(pcii->hInstServer);
|
|
*pidInst = HandleToUlong(pcii->hInstClient);
|
|
if (pcii->hInstClient == 0) {
|
|
LeaveDDECrit;
|
|
NtUserCallOneParam((ULONG_PTR)pcii->hInstServer, SFI__CSDDEUNINITIALIZE);
|
|
EnterDDECrit;
|
|
uiRet = DMLERR_MEMORY_ERROR;
|
|
goto Backout;
|
|
}
|
|
SetHandleData(pcii->hInstClient, (ULONG_PTR)pcii);
|
|
|
|
pcii->next = pciiList;
|
|
pciiList = pcii;
|
|
if (fUnicode) {
|
|
pcii->flags |= IIF_UNICODE;
|
|
}
|
|
uiRet = DMLERR_NO_ERROR;
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (uiRet);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Description:
|
|
* Shuts down a DDEML instance and frees all associated resources.
|
|
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
*/
|
|
BOOL DdeUninitialize(DWORD idInst)
|
|
{
|
|
PCL_INSTANCE_INFO pcii, pciiPrev;
|
|
BOOL fRet = FALSE;
|
|
|
|
CheckDDECritOut;
|
|
EnterDDECrit;
|
|
|
|
pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
|
|
if (pcii == NULL) {
|
|
BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* If this thread is in the middle of a synchronous transaction or
|
|
* a callback, we need to back out of those first.
|
|
*/
|
|
if ((pcii->flags & IIF_IN_SYNC_XACT) || pcii->cInDDEMLCallback) {
|
|
pcii->afCmd |= APPCMD_UNINIT_ASAP;
|
|
fRet = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
ApplyFunctionToObjects(HTYPE_CONVERSATION_LIST, InstFromHandle(pcii->hInstClient), (PFNHANDLEAPPLY)DdeDisconnectList);
|
|
ApplyFunctionToObjects(HTYPE_CLIENT_CONVERSATION, InstFromHandle(pcii->hInstClient), (PFNHANDLEAPPLY)DdeDisconnect);
|
|
ApplyFunctionToObjects(HTYPE_SERVER_CONVERSATION, InstFromHandle(pcii->hInstClient), (PFNHANDLEAPPLY)DdeDisconnect);
|
|
ApplyFunctionToObjects(HTYPE_ZOMBIE_CONVERSATION, InstFromHandle(pcii->hInstClient), (PFNHANDLEAPPLY)WaitForZombieTerminate);
|
|
ApplyFunctionToObjects(HTYPE_DATA_HANDLE, InstFromHandle(pcii->hInstClient), (PFNHANDLEAPPLY)ApplyFreeDataHandle);
|
|
|
|
LeaveDDECrit;
|
|
NtUserCallOneParam((ULONG_PTR)pcii->hInstServer, SFI__CSDDEUNINITIALIZE);
|
|
NtUserDestroyWindow(pcii->hwndMother);
|
|
EnterDDECrit;
|
|
|
|
DDEMLFree(pcii->plaNameService);
|
|
DestroyInstance(pcii->hInstClient);
|
|
|
|
// unlink pcii from pciiList
|
|
|
|
if (pciiList == pcii) {
|
|
pciiList = pciiList->next;
|
|
} else {
|
|
for (pciiPrev = pciiList; pciiPrev != NULL && pciiPrev->next != pcii; pciiPrev = pciiPrev->next) {
|
|
;
|
|
}
|
|
if (pciiPrev != NULL) {
|
|
pciiPrev->next = pcii->next;
|
|
}
|
|
}
|
|
DDEMLFree(pcii);
|
|
fRet = TRUE;
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (fRet);
|
|
}
|
|
|
|
|
|
/*
|
|
* Description:
|
|
* Registers, and Unregisters service names and sets the Initiate filter
|
|
* state for an instance.
|
|
|
|
* History:
|
|
* 11-1-91 sanfords Created.
|
|
*/
|
|
HDDEDATA DdeNameService(
|
|
DWORD idInst,
|
|
HSZ hsz1, // service name
|
|
HSZ hsz2, // reserved for future enhancements
|
|
UINT afCmd) // DNS_ flags.
|
|
{
|
|
BOOL fRet = TRUE;
|
|
LATOM *plaNameService;
|
|
PCL_INSTANCE_INFO pcii;
|
|
|
|
EnterDDECrit;
|
|
|
|
pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
|
|
if (pcii == NULL) {
|
|
BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if ((hsz1 && ValidateHSZ(hsz1) == HSZT_INVALID) || hsz2 != 0) {
|
|
SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (afCmd & DNS_FILTERON && !(pcii->afCmd & APPCMD_FILTERINITS)) {
|
|
pcii->afCmd |= APPCMD_FILTERINITS;
|
|
NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, pcii->afCmd);
|
|
}
|
|
if (afCmd & DNS_FILTEROFF && (pcii->afCmd & APPCMD_FILTERINITS)) {
|
|
pcii->afCmd &= ~APPCMD_FILTERINITS;
|
|
NtUserUpdateInstance(pcii->hInstServer, &pcii->MonitorFlags, pcii->afCmd);
|
|
}
|
|
|
|
if (afCmd & (DNS_REGISTER | DNS_UNREGISTER)) {
|
|
GATOM ga;
|
|
|
|
if (pcii->afCmd & APPCMD_CLIENTONLY) {
|
|
SetLastDDEMLError(pcii, DMLERR_DLL_USAGE);
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (hsz1 == 0) {
|
|
if (afCmd & DNS_REGISTER) {
|
|
/*
|
|
* registering NULL is not allowed!
|
|
*/
|
|
SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER);
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* unregistering NULL is just like unregistering each
|
|
* registered name.
|
|
|
|
* 10/19/90 - made this a synchronous event so that hsz
|
|
* can be freed by calling app after this call completes
|
|
* without us having to keep a copy around forever.
|
|
*/
|
|
plaNameService = pcii->plaNameService;
|
|
while (*plaNameService != 0) {
|
|
ga = LocalToGlobalAtom(*plaNameService);
|
|
DeleteAtom(*plaNameService);
|
|
LeaveDDECrit;
|
|
RegisterService(FALSE, ga, pcii->hwndMother);
|
|
EnterDDECrit;
|
|
GlobalDeleteAtom(ga);
|
|
plaNameService++;
|
|
}
|
|
pcii->cNameServiceAlloc = 1;
|
|
*pcii->plaNameService = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
if (afCmd & DNS_REGISTER) {
|
|
plaNameService = (LATOM *)DDEMLReAlloc(pcii->plaNameService, sizeof(LATOM) * ++pcii->cNameServiceAlloc);
|
|
if (plaNameService == NULL) {
|
|
SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR);
|
|
pcii->cNameServiceAlloc--;
|
|
fRet = FALSE;
|
|
goto Exit;
|
|
} else {
|
|
pcii->plaNameService = plaNameService;
|
|
}
|
|
IncLocalAtomCount(LATOM_FROM_HSZ(hsz1)); // NameService copy
|
|
plaNameService[pcii->cNameServiceAlloc - 2] = LATOM_FROM_HSZ(hsz1);
|
|
plaNameService[pcii->cNameServiceAlloc - 1] = 0;
|
|
} else { // DNS_UNREGISTER
|
|
plaNameService = pcii->plaNameService;
|
|
while (*plaNameService != 0 && *plaNameService != LATOM_FROM_HSZ(hsz1)) {
|
|
plaNameService++;
|
|
}
|
|
if (*plaNameService == 0) {
|
|
goto Exit; // not found just exit
|
|
}
|
|
// fill empty slot with last entry and fill last entry with 0
|
|
pcii->cNameServiceAlloc--;
|
|
*plaNameService = pcii->plaNameService[pcii->cNameServiceAlloc - 1];
|
|
pcii->plaNameService[pcii->cNameServiceAlloc - 1] = 0;
|
|
}
|
|
|
|
ga = LocalToGlobalAtom(LATOM_FROM_HSZ(hsz1));
|
|
LeaveDDECrit;
|
|
RegisterService((afCmd & DNS_REGISTER) ? TRUE : FALSE, ga,
|
|
pcii->hwndMother);
|
|
EnterDDECrit;
|
|
GlobalDeleteAtom(ga);
|
|
}
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return ((HDDEDATA)IntToPtr( fRet ));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Description:
|
|
* Returns last error code set for the instance given.
|
|
|
|
* History:
|
|
* 11-12-91 sanfords Created.
|
|
*/
|
|
UINT DdeGetLastError(DWORD idInst)
|
|
{
|
|
UINT uiRet = 0;
|
|
PCL_INSTANCE_INFO pcii;
|
|
|
|
EnterDDECrit;
|
|
|
|
pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
|
|
if (pcii == NULL) {
|
|
uiRet = DMLERR_INVALIDPARAMETER;
|
|
goto Exit;
|
|
}
|
|
uiRet = pcii->LastError;
|
|
pcii->LastError = DMLERR_NO_ERROR;
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (uiRet);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Description:
|
|
* Does security impersonation for DDEML server apps.
|
|
* This API should only be called with server side hConvs;
|
|
|
|
* History:
|
|
* 5-4-92 sanfords Created.
|
|
*/
|
|
BOOL DdeImpersonateClient(HCONV hConv)
|
|
{
|
|
PCONV_INFO pcoi;
|
|
PCL_INSTANCE_INFO pcii;
|
|
BOOL fRet = FALSE;
|
|
|
|
EnterDDECrit;
|
|
|
|
pcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_SERVER_CONVERSATION, HINST_ANY);
|
|
if (pcoi == NULL) {
|
|
BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
|
|
goto Exit;
|
|
}
|
|
pcii = PciiFromHandle((HANDLE)hConv);
|
|
if (pcii == NULL) {
|
|
BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER);
|
|
goto Exit;
|
|
}
|
|
|
|
fRet = NtUserImpersonateDdeClientWindow(pcoi->hwndPartner, pcoi->hwndConv);
|
|
|
|
Exit:
|
|
LeaveDDECrit;
|
|
return (fRet);
|
|
} |