cancel
Showing results for 
Search instead for 
Did you mean: 

Again c++ question

Former Member
0 Kudos

Ok...I have finally managed to get a connection via my

MFC application. But how can i get a connection to a

already opened and aktive session???

Actually i used this, but it always opens a complete

new Connection with new login.....


_Dsapfewse p;

if(p.CreateDispatch(p.GetClsid()))
{
  LPDISPATCH disp = NULL;
  VARIANT v1, v2;

  VariantInit(&v1);
  VariantInit(&v2);

  disp = p.OpenConnectionByConnectionString("servername", v1, v2);
  ISapConnectionTarget con(disp);

  ISapSessionTarget session(child.ElementAt(0));
}

Also, if i try to login in the new created session,

sap is not able to connect. It ends the connection in my

application and gives a runtime error in sap!

Anyone cn help...or any ideas??

Accepted Solutions (0)

Answers (4)

Answers (4)

Former Member
0 Kudos

I am doing the same things mentioned in this thread - and creating the autogenerated class by going through the msdn documentation at "How to create an automation project using MFC and a type library"

I have written an application which attaches to sap gui and then releases it.

I am calling m_sapSession->ReleaseDispatch(); in the destructor . But it does not seems to release the sap gui session. I am confirming by the gui animation at the right bottom corner which is still running. Could there be any bug with MFC autogenerating the classes like I always have to change the statements within function which returns one of the autogenerated class.

Any pointers would be appreciated.

Former Member
0 Kudos

Here is the solution:

CoInitialize(NULL);

_Dsapfewse* app;

LPUNKNOWN u = _GetRunningObject(L"SAPGUI");

if(!u)

return;

HRESULT hr;

IDispatch *pDisp;

hr = u->QueryInterface(IID_IDispatch, (void **)&app);

ASSERT(!FAILED(hr));

u->Release();

CComPtr<_Dsapfewse> guiApp = NULL;

CComPtr<IDispatch> active_session;

CComPtr<ISapCollectionTarget> connection;

CComPtr<ISapComponentTarget> sessions;

CComPtr<ISapSessionTarget> as ;

CComPtr<ISapGenericCollection> gc ;

CComPtr<ISapComponentTarget> text1;

guiApp = CComPtr<IDispatch>(app->GetScriptingEngine());

long mv = long(guiApp->GetMajorVersion());

as = CComPtr<IDispatch>(guiApp->ActiveSession);

bstrt strName = as->Name;

gc = as->FindByPosition(m_point.x,m_point.y);

bstrt text = gc->Item(0);

text1 = CComPtr<IDispatch>(as->FindById(text));

bstrt str = text1->GetName();

//CoUninitialize();

Message was edited by:

zoltan fleisz

Former Member
0 Kudos

I get 'undeclared identifier' for ISapCollectionTarget .

Do I need to use:

#import "c:\Program Files\SAP\FrontEnd\SAPgui\sapfewse.ocx" ?

If I'm using it I get it in the intellisense but I still get the same eror. I can only use

SAPFEWSELib::ISapCollectionTarget

but still, the code below doesn't run, I get an error saying that I can't instantiate an abstract class...

Do I need to include something else?

Thanks

Message was edited by:

Naoki Nonagase

Former Member
0 Kudos

Sure

using namespace SAPFEWSELib;

)

Regards,

Z

Former Member
0 Kudos

Hi there,

And what about vc++2005. There is no class wizard anymore. Instead I've used the #import directive but in this case the wrapper classes are directly derived from IDispatch and not from COleDispatchDriver class. Thus the AttachDispatch and CreateDispatch part of your codes must be replaced with something else.

The ROT part is working fine.

BUT!

Dsapfewse p ;

// Dsapfewse is an abstract class so p cannot be declared

// using CreateInstance from __uuid(xxxx) also failed

if(p->CreateDispatch(IID_ISAP_R3_APPLICATION)) // there is no CreatDispatch for IDispatch

{

LPDISPATCH disp = NULL;

p.AttachDispatch(d);

// ...

}

Any idea would be appreciated.

Thanx in advance

Zoltan

Former Member
0 Kudos

For people, who will have similare problems, you have

to use the IRunningObjectTable interface to get the

interface to the SapLogon application and then you

can get the ScriptingEngine from that interface.

PS: I had to implement the GetScriptingEngine Method

in GuiApplication by myself, because it was declared as

hidden in the ocx-File (viewed with OleViewer).

Message was edited by: Mesut Büyüktokatli

Former Member
0 Kudos

hi,

I tray to use "IRunningObjectTable" interface to get the

interface to the SapLogon application and then you

can get the ScriptingEngine from that interface. I used this code:

CreateBindCtx( 0, &instance );

instance->GetRunningObjectTable(&ppIRunningObjectTable);

if(hr==S_OK){

cout<<"\n hr(S_OK) = "<< hr;

ppIRunningObjectTable->EnumRunning(&ppIEnumMoniker);

}

else

cout<<"\n hr(nonS_OK) = "<< hr;

but when I have "IRunningObjectTable" (ppIRunningObjectTable), I don't known How to do to get the interface to the SapLogon application and then you

can get the ScriptingEngine from that interface.

Anyone can help me

thks

Former Member
0 Kudos

Well here is my code to get access to the ScriptingEngine:

First I made a little Function to get the Object from the

RunningObjectTable.

LPUNKNOWN GetRunningObject(const wchar_t* pName)

{

IRunningObjectTable* Table = NULL;

LPUNKNOWN u = NULL;

IBindCtx* pbcfull = NULL;

if(CreateBindCtx(0, &pbcfull) != S_OK)

return NULL;

if(pbcfull->GetRunningObjectTable(&Table) == S_OK)

{

IEnumMoniker* pEnumMoniker = NULL;

if(Table->EnumRunning(&pEnumMoniker) == S_OK)

{

IMoniker* pCurMoniker = NULL;

while(pEnumMoniker->Next(1, &pCurMoniker, NULL) == S_OK)

{

LPOLESTR ppszDisplaynamefull;

if(pCurMoniker->GetDisplayName(pbcfull, NULL, &ppszDisplaynamefull) == S_OK)

{

if(wcscmp(ppszDisplaynamefull, pName) == 0)

{

HRESULT hr;

hr = Table->GetObject(pCurMoniker, &u);

if(hr == S_OK)

{

pCurMoniker->Release();

break;

}

}

pCurMoniker->Release();

}

}

pEnumMoniker->Release();

}

Table->Release();

}

pbcfull->Release();

return u;

}

Now here is the part, where i get access to the ScriptingEngine:

LPDISPATCH d = NULL;

LPUNKNOWN u = GetRunningObject(L"SAPGUI");

if(!u)

return NULL;

if(u->QueryInterface(IID_IDispatch, (void**)&d) != S_OK)

{

u->Release();

return;

}

Dsapfewse p;

if(p.CreateDispatch(IID_ISAP_R3_APPLICATION))

{

LPDISPATCH disp = NULL;

p.AttachDispatch(d);

disp = p.GetScriptingEngine();

Dsapfewse* m_GUIApplication = new Dsapfewse(disp);

}

The Dsapfewse class you can let generate from visual studio. If you do not know how, just let me know..

hope this helps

Message was edited by: Mesut Büyüktokatli

Former Member
0 Kudos

Hi Mesut

I try to test your code. for the Dsapfewse class or _Dsapfewse I did this: références->ajout->COM->sapfewse.ocx (SAP Scripting Control). what to create 2 DLLs in my project (Interop.SAPFEWSELib.dll and stdole.dll). but with compilation, he does not know Dsapfewse.

Then how to make to have the class Dsapfewse (or _Dsapfewse?).

thank you.

Former Member
0 Kudos

Well, you need to generate wrapper classes from an

ocx, dll or tlb file. I explain you, how to do

in Visual Studio 6:

Start your class wizard and and select

'From a type library'.

There you have to select the Type Library for that you

want to create the wrapper classes (ocx, dll, tlb...).

You will need the sapfewse.ocx file that will be in the

SapGui folder. If you selected the file, you will have

to select all interfaces (you casn use Mouse to select

all). After selectig the interfaces, press ok and your

wrapper classes willl be generated...

Problems, try this page:

http://www.murrayc.com/learning/windows/usecomfromMFC.shtml

Former Member
0 Kudos

Oh, the method 'GetScriptingEngine' will not be generated,

it is marked as hidden. You can see that by browsing the

ocx-file with the OLE Viewer.

But you can implement it in the 'Dsapfewse-class'!!

Just add the method in the header:

LPDISPATCH GetScriptingEngine();

The method will look like this:

LPDISPATCH Dsapfewse::GetScriptingEngine()

{

LPDISPATCH result;

InvokeHelper(0x0001, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, NULL);

return result;

}

Former Member
0 Kudos

when I generate wrapper classes from a sapfewse.ocx file, there are classes which I have

renamed such as CSapCollectionTarget in GuiComponentCollection. but I do not manage to

recover a connection and after a session. like this with the vc++ program:

Set connection = application.Children(0) 'connection

Set session = connection.Children(0) 'session

I have tried this:

CDsapfewse p;

LPCTSTR lpszProgID = "Sapgui.Application";//"SapScriptingCtrl.1";

COleException* pError = NULL;

if(p.CreateDispatch(lpszProgID, pError /IID_ISap_R3_Application/ ))

{

LPDISPATCH disp = NULL;

p.AttachDispatch(d);

disp = p.GetScriptingEngine();

CDsapfewse* m_GUIApplication = new CDsapfewse(disp);

GetDlgItem(IDC_EDIT1)->SetWindowText(m_GUIApplication->GetType());

//the previous part is well. but it's the next which doesn't go

//Set connection = application.Children(0)

GuiComponentCollection *pCompCol = m_GUIApplication->GetChildren();// or GetConnections()

LPDISPATCH disp2 = pCompCol->m_lpDispatch;

CSapConnectionTarget* m_GUIConnection = new CSapConnectionTarget(disp2);

m_GUIConnection->AttachDispatch(disp4);

GetDlgItem(IDC_EDIT3)->SetWindowText(m_GUIConnection->GetType());

/*tis generate error execution */

...

}

thus I do not know too much how to make.

Can somebody it help me.

thx!

Former Member
0 Kudos

Ok, I see you generated the wrappers...

Look that is how i use it...and connection does work,

but you need to work with Hooks!

Before instlling the Hook i initialise the Scripting Engine:


// Do not remember where i got that connstant from...
// I think it is created with the wrapper classes!
// Should be in the header of the wrapper class.
static const IID IID_ISAP_R3_APPLICATION =
{ 0xB90F32AD, 0x859E, 0x4EDD, { 0xBF, 0xAE, 0xC9, 0x21, 0x68, 0x49, 0x52, 0xC } };

// These 2 are global variables, that shall be 
// visible for the main Application!!!
Dsapfewse* m_GUIApplication = NULL;
ISapSessionTarget* m_SAPSession = NULL;

// The following is needed in the Hook code!!
LPDISPATCH d = NULL;

LPUNKNOWN u = _GetRunningObject(L"SAPGUI");
if(!u)
  return NULL;

if(u->QueryInterface(IID_IDispatch, (void**)&d) != S_OK)
{
  u->Release();
  return NULL;
}
Dsapfewse p;

if(p.CreateDispatch(IID_ISAP_R3_APPLICATION))
{
  LPDISPATCH disp = NULL;

  p.AttachDispatch(d);		
  disp = p.GetScriptingEngine();
  m_GUIApplication = new Dsapfewse(disp);
  disp = m_GUIApplication->GetConnections();
  if(disp)
  {
    ISapCollectionTarget cons(disp);

    if(cons.GetCount()>0)
    {
      disp = cons.ElementAt(0);
      if(disp)
      {
        ISapConnectionTarget con(disp);
        disp = con.GetSessions();
        if(disp)
        {
          ISapCollectionTarget ses(disp);
          long co = ses.GetCount();
          if(co>0)
          {
            disp = ses.ElementAt(0);
            m_SAPSession = new ISapSessionTarget(disp);
          }
        }
      }
    }
  }
}


LPUNKNOWN _GetRunningObject(const wchar_t* pName)
{
	IRunningObjectTable* Table = NULL;
	LPUNKNOWN u = NULL;
	IBindCtx* pbcfull = NULL;

	if(CreateBindCtx(0, &pbcfull) != S_OK)
		return NULL;

	if(pbcfull->GetRunningObjectTable(&Table) == S_OK)
	{
		IEnumMoniker* pEnumMoniker = NULL;
		if(Table->EnumRunning(&pEnumMoniker) == S_OK)
		{
		   IMoniker* pCurMoniker = NULL;

			while(pEnumMoniker->Next(1, &pCurMoniker, NULL) == S_OK)
			{
				LPOLESTR ppszDisplaynamefull;

				if(pCurMoniker->GetDisplayName(pbcfull, NULL, 
                                   &ppszDisplaynamefull) == S_OK)
				{
					if(wcscmp(ppszDisplaynamefull, pName) == 0)
					{
						HRESULT hr;
						hr = Table->GetObject(pCurMoniker, &u);
						if(hr == S_OK)
						{
							pCurMoniker->Release();
							break;
						}
					}
					pCurMoniker->Release();
				}
			}
			pEnumMoniker->Release();
		}
		Table->Release();
	}
	pbcfull->Release();

	return u;
}

The hook will send the mouseposition to my main Programm,

where i can get use of it. I send you my example methode

to use the sended Mousecoordinates:


LRESULT CPowerTrackerView::OnMouseMsg(WPARAM wParam, LPARAM lParam)
{
	m_SAPSession = CHook::GetSAPSession();
	if((m_SAPSession) && ((UINT)wParam == WM_LBUTTONDOWN))
	{
		VARIANT vt;
		ANALYSE_DATA data;
		LPDISPATCH disp = NULL;

		GetCursorPos(&data.pt);

		VariantInit(&vt);
		vt.vt = VT_BOOL;
		vt.boolVal = false;

		try
		{
			disp = m_SAPSession->FindByPosition(data.pt.x, data.pt.y, vt);
			if(disp)
			{
				ISapGenericCollection col(disp);
				if (col)
				{
// Do anything with the found Objekt!!
				}
			}
			else
			{
                            Error
			}
		}
		catch (COleException* e)
		{
			e->Delete();
			AddLine(L"COleException occured in Module OnMouseMsg!");
			return -1;
		}
	}
	return 0;
} // CHookDlg::OnMyMouseMove

Hope this helps....

Message was edited by: Mesut Büyüktokatli

Message was edited by: Mesut Büyüktokatli

Message was edited by: Mesut Büyüktokatli

Former Member
0 Kudos

Hi Mesut Büyüktoka ,

Your work regarding SAPgui hooking using C++ really helped me a lot. I have done the hooking part. But FindByPosition is not returning any thing infact it gets stuck in there after debugging i found it stucks at function below:

SCODE sc = m_lpDispatch->Invoke(dwDispID, IID_NULL, 0, wFlags,&dispparams, pvarResult, &excepInfo, &nArgErr);

and sap also generated a trc file in which i found this:

Error LoadSymbolFile('C:WINDOWSsystem32MFC71.DLL'): 126

Any help will be highly appreciated and many thanks in advance.

Regards,

Arslan Ahmed

Message was edited by:

Arslan Ahmed

Message was edited by:

Arslan Ahmed

Former Member
0 Kudos

Hi Mesut,

Everything is working fine (SAPGui object, connection and session) except for

disp = m_SAPSession->FindByPosition(data.pt.x, data.pt.y, vt);

It is not returning anything if last parameter is true and it returns null if last parameter is set to false. I am giving it screen co-ordinates whenever clicked on some control in SAP client.

Is there any alternative to this or Any particular requirement for using FindByPosition?

Regards,

Arslan Ahmed.

Former Member
0 Kudos

Hi,

Thanks for having patience. I have solved my problem of findByPosition. It is working now in C++ and VBS both.

Regards,

Arslan Ahmed.

Former Member
0 Kudos

Hi,

Thank you very much for all the information!

do you know how to use the sap events (startRequestEvent, EntRequestEvent etc.) from c++ ?

Thanks

Message was edited by:

Naoki Nonagase