on 03-29-2006 3:13 PM
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??
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
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
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
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.
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:
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;
}
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!
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
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
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.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.