|
Hi all,
I am working on an application that is written in Java. It's basically a middleware server. The client is a Java application. However, there's a need to develop an Excel client. I have been provided with an addin that has certain functions that the VBA can call. The other side of the COM DLL is made of c++ programs that use JNI to pass data to Java and receive results. I have successfully created new functions to work on this.
When I started working on this I created a '|' delimited string to pass data from Excel to COM to Java and vice versa. The strings looked like this:
|Property1=Value1|Property2=Vaue2|........|PropertN=ValueN|
In the early stages these functions that I had created were simple atomic functions i.e. take in one string spit out resultant string. Now, however I need to be able to send arrays of such strings and also receive results in the form of arrays of strings.
I used CComSafeArray to do so.
Here's the code of what I did
STDMETHODIMP CAddin::MyClass_LoadVals(VARIANT ValIds, VARIANT* outVals)<br />
{<br />
<br />
USES_CONVERSION;<br />
std::list<std::string> result;<br />
std::list<std::string> inpArr;<br />
<br />
CComVariant var;<br />
<br />
CComSafeArray<bstr> parr;<br />
CComBSTR* bstrs;<br />
var.Attach(&valIds);<br />
parr.Attach(var.parray);<br />
<br />
int dim = parr.m_psa->cDims;<br />
if (parr.m_psa->cDims != 1)<br />
return S_FALSE;<br />
<br />
if(parr.m_psa->rgsabound->cElements > 1)<br />
{<br />
SafeArrayAccessData(parr,reinterpret_cast<void **="">(&bstrs));<br />
for (int i=0;i < parr.m_psa->rgsabound->cElements;i++)<br />
{<br />
std::string tmp;<br />
tmp = W2CA(bstrs[i]);<br />
inpArr.push_back(tmp);<br />
}<br />
}<br />
SafeArrayUnaccessData(parr.m_psa);<br />
<br />
VariantInit(outVals);<br />
<br />
if(JavaInterface::JavaInterface_LoadVals(inpArr,result)){<br />
outVals->vt=VT_ARRAY|VT_BSTR;<br />
createStringArrayVariant(outVals,result);<br />
return S_OK;<br />
}else{<br />
getCalypsoError();<br />
}<br />
<br />
return S_OK;<br />
}</void></bstr></std::string></std::string>
Code for createStringArrayVariant(VARIANT,std::list<std::string> :-
<br />
bool createStringArrayVariant(VARIANT* to, std::list<std::string>& from)<br />
{<br />
VariantInit(to);<br />
SAFEARRAYBOUND bound = {from.size(), 0};<br />
SAFEARRAY* array = ::SafeArrayCreate(VT_VARIANT, 1, &bound);<br />
<br />
long index = 0;<br />
VARIANT v; VariantInit(&v);<br />
for(std::list<std::string>::iterator i = from.begin(); i != from.end(); i++)<br />
{<br />
convertStringToVariant(&v, *i);<br />
::SafeArrayPutElement(array, &index, (void*)&v); ++index;<br />
}<br />
to->vt = VT_VARIANT | VT_ARRAY;<br />
to->parray = array;<br />
return true;<br />
}</std::string></std::string>
Please bear in mind that createStringArrayVariant(...) function was provided to me with the product that I am working on.
The resultant output is correctly passed to Excel. I load it as a variant array and try and do further processing. However, the problem is when the output is loaded, Excel starts crashing while doing simple things like updating values in the cells or running a simple loop. These parts of VBA code work fine in isolation i.e. without loading that array of values. Sometimes when Excel crashes, it just simply disappears without so much as an error report. My logs for the addin and the logs for Java, none of them indcate anything. Is the array too big or is this sort of programming not advisable for linking VBA and C++. I really need this to work. Any help would really be appreciated.
Please bear in mind that I have little experience with C++ and almost no exprience with Visual C++, prior to working on this project. Whatever I have learnt is from the existing code or Google, so I could be quite wrong with my code here.
I'd appreciate any leads in this matter.
Thanks for your help
Sukant Saddi
|
|
|
|
|
Hi Sukant,
Looking at your code, I would say that createStringArrayVariant should change a little.
Create your safe array as ::SafeArrayCreate(VT_BSTR, 1, &bound); .
I am saying this because your MyClass_LoadVals seems to expect that. Also, it is much easier to use:
CComBSTR str = parr.GetAt(index);
than your call to SafeArrayAccessData
Anyway, my guess is your data has been destroyed. CComVariant var; is not really necessary, use parr.Attach(ValIds.parray);
You should detach it as well.
God bless,
Ernest Laurentin
|
|
|
|
|
Hi all,
I wrote a DLL in C#, and exposed some functions to COM interop by following these guidelines:
-declare a custom constructor
-declare the functions to be exposed as public.
-declare an interface that the class implements.
-created a type library (.tlb) using regasm.
Now the DLL functions can be viewed and accessed from an unmanaged language such as VB6 (tested it and it works).
The problem is that another C++ developer wants to use this DLL on another machine to create an application that would be distributed to clients.
What should steps should be done so the developer could successfully use this DLL in his code as well as the end users who will deploy and use the application?
Thank you for your help.
|
|
|
|
|
|
Hi
I’m facing one major issues mentioned below in my HostEmulatorClient application which is using "Attachmate EXTRA! X-treme 9.0" COM component.
- I created a windows form to connect with ORBIT system using EXTRA component. It is
working fine. I can open & view PTs with Phase status as “Await”. Now I have converted this
form into a window service as being a project requirement but my window service is not able to
connect with ORBIT system using the EXTRA component. My Window Service is updating a local log
file. Even in this log file there is no error/exception logged. I’m not able to trace the issue
here.
From code level I do not see any problem. These problems may be because of some missed configuration which I’m not aware about. Below is the code where I try to connect
with ORBIT system.
public bool Open()
{
try
{
EXTRA._System sys = new EXTRA.ExtraSystemClass();
EXTRA.Sessions sss = new EXTRA.ExtraSessionsClass();
EXTRA._Session ses;
EXTRA.Screen scr;
string str = sys.DefaultFilePath;
LogHelper.WriteLog("Path : " + str + "\\" + _AccessDetail.EmulatorFileName + ".EDP", LoggingCategory.AllLoggingMessgesLog);
//LOG IS GENERATED ONLY TILL THIS LEVEL. THERE IS NO LOG FOR LATER LOG STATEMENTS, LIKE LOG FOR EXCEPTION OCCURRED ETC
ses = (EXTRA.ExtraSession)sss.Open(str + "\\" + _AccessDetail.EmulatorFileName + ".EDP");
scr = (EXTRA.ExtraScreen)ses.Screen;
LogHelper.WriteLog("Session instance created ", LoggingCategory.AllLoggingMessgesLog);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLog("Exception occured : " + ex.ToString(), LoggingCategory.AllLoggingMessgesLog);
throw ex;
}
}
Please if anyone around there has faced such issue & has got the solution or at least the cause for
this issue please share it.
Thanks
Kamal Chauhan
|
|
|
|
|
is it a permissions issue ? - most services by default run in the LocalSystem account - this has no access to Network functions
'g'
|
|
|
|
|
My service, called HostEmulatorService is running under the following account:
NT AUTHORITY\LocalService
If this is the possible cause for the issue I'm facing, please suggest the way out.
Thanks
Kamal Chauhan
|
|
|
|
|
I'm writing my first shell extension dll, and I'm trying to figure out how to pass the Recycle bin files/folders anme CShellExt::InvokeCommand at right click of menu item. I am getting others files and folders name.
Some sennipt is attached.
<br />
void CCoMenHandler::GetSelectedFiles(LPCITEMIDLIST pidlFolder,IDataObject *pdtobj)<br />
{<br />
g_szSelectedFiles.RemoveAll();<br />
<br />
if (pdtobj) <br />
{<br />
pdtobj->AddRef();<br />
<br />
STGMEDIUM medium;<br />
FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};<br />
<br />
<br />
HRESULT hr = pdtobj->GetData (&fe, &medium);<br />
if (FAILED (hr))<br />
{<br />
return ;<br />
}<br />
<br />
char path[MAX_PATH];<br />
<br />
UINT fileCount = DragQueryFile((HDROP)medium.hGlobal, 0xFFFFFFFF,<br />
path, MAX_PATH);<br />
<br />
if (fileCount>0)<br />
{<br />
g_szSelectedFiles.SetSize(fileCount);<br />
<br />
for (UINT i=0;i<fileCount;i++) <br />
{<br />
memset(path, 0, MAX_PATH);<br />
if (DragQueryFile((HDROP)medium.hGlobal, i, path, MAX_PATH)) <br />
{<br />
g_szSelectedFiles.SetAt(i, path);<br />
}<br />
}<br />
<br />
g_szSelectedFiles.FreeExtra();<br />
}<br />
<br />
ReleaseStgMedium(&medium);<br />
}<br />
<br />
<br />
}<br />
Thanx in advance.:
|
|
|
|
|
Hi I have a RTD Server that work with the application EXCEL.
I retrieve the information with cell function like this:
=RTD("progID","", "topic1", "topic2","topic3","topic4","topic5")
With some research on Google. I try to retrieve the data programmatically
Excel.Application excel = new Excel.ApplicationClass();
excel .WorksheetFunction.RTD("progID", "", "topic1", "topic2", "topic3", "topic4", "topic5");
and I have this error at compilation
No overload for method 'RTD' takes '7' arguments
Did anyone know how to retrieve data programmatically from rtd server with callback function
Thank you
Bang
|
|
|
|
|
Hi,
I have a COM dll, in which there are many interaces/objects. Threre is a one object which all other objects are retrieved.
It means I need one CoCreateInstance() to initialize top level of object(TopObject).
Other object are initialize like :
Otherbject1=TopObject->Store;
Otherbject2=TopObject->Add->File;
Is this Correct?
TopObject->Release();
Otherbject1->Release();
Otherbject2->Release();
If not then which objects I have to release?
|
|
|
|
|
pther wrote: Is this Correct?
Yes, the tricky handling of interface reference count for such objects must be handled by the COM server (i.e. your TopObject).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Consider an MFC Activex control, Example, Vehicle,
Following are the interfaces,
_DVehicle , _DVehicleEvents - Default interfaces.
ICar - Custom interfaces.
The default interface (_DVehicle) returns pointer to ICar interface for accessing the ICar methods/properties.
1. Now , I need to add new methods/properties/Events to the above
interfaces. Since modifying the existing interfaces is against the rules,
How do I go about it?
2. If I write a new interface ICar2, then what will happen to the old
applications that are using old interface ICar ? How will the default (_DVehicle) interface decide which interface pointer it should return?
3. How do I add a new Event Interface?
4. What is the purpose of changing type library version. If I add a new
interface then do I have to change the major version of the type library (Ex:
1.0 - 2.0) ?
|
|
|
|
|
Sir,
My COM class not getting registered.
Iam trying to register the COM DLL with .regsvr32.
It is not displaying either Dll Registered or Failed messge.
So, when i try to create instance of thet class, using CoCreateInstance
it returned Failure Code -2147221164 , that means Class not registered.
I want to know the reasons of CoCreateInstance failure.
Help me Plz.
Krishna.
|
|
|
|
|
Are you using /s ?
Usage: regsvr32 [/u] [/s] [/n] [/i[:cmdline]] dllname
/u - Unregister server
/s - Silent; display no message boxes
/i - Call DllInstall passing it an optional [cmdline]; when used with /u calls dll uninstall
/n - do not call DllRegisterServer; this option must be used with /i
---------------------------
OK
---------------------------
Following might help for error messages
http://support.microsoft.com/kb/249873[^]
Sohail
modified 21-Apr-21 21:01pm.
|
|
|
|
|
Iam able to register my DLL After small modification in project settings.
I removed _WinmainCrtstartup in Entry point symbol tab.
|
|
|
|
|
Hi,
My dev environment is VC++ .NET 2005 with MFC.
So here's the deal:
From my main application, I load up a number of dlls as COM objects with CreateInstance.
- These dlls are all registered.
- Everything works perfectly when the dlls are compiled in debug mode.
- When the dlls are compiled in release mode, CreateInstance fails to load one of the dlls from my main application, returning error -2147221164, CLASS_NOT_REGISTERED. This only happens with one dll - if I replace that dll with a debug version of the same dll, everything works fine.
I don't have any #ifdef _DEBUG sections in the dll code.
Has anyone seen this before or know what might be wrong?
KR
|
|
|
|
|
Hi Kelly, iam also facing same problem.
My CoCreateinstance is failed to return correct pointer. It is just retuned the error code -2147221164.
I dont know what to do....
Please advice us to resolve this problem.
|
|
|
|
|
KellyR wrote: I don't have any #ifdef _DEBUG sections in the dll code.
And haven't you ASSERT at all (or have you only harmless ASSERT, i.e. without meaningful code inside)?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
The only asserts I have are ASSERT(0).
KR
|
|
|
|
|
Have a look at http://www.flounder.com/debug_release.htm[^].
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Can I pass the registry key directly into CreateInstance instead of using a CLSID? How would I do that? I have the registry key as a string but I can't find a way to convert that string to a CLSID or pass it to CreateInstance.
Thanks!
KR
|
|
|
|
|
Could you show me your code?
|
|
|
|
|
Well it's just a CreateInstance call with a CLSID. It's like this:
m_Server.CreateInstance(SERVERLib::CLSID_Server);
And the CLSID passed into the function is correct in both debug and release versions. The dll is registered, I just don't understand why it won't load in release mode.
KR
|
|
|
|
|
I think you need to have the MFC Dlls for VS2005 in the system where you are testing the app.
However if you are testing it in the same system where VS 2005 is installed there is some other problem
"Every morning I go through Forbes list of 40 richest people in the world. If my name is not in there, I go to work..!!!"
|
|
|
|
|
Hi All,
I implemented a C# class library and registered it to be visible for COM objects, then i used it from VB6 application and it works fine. Now the problem is that i want to raise an event in the .NET COM and pass it as an event in VB6. i.e. when the .NET COM catched an exception i want it to raise event in the VB6 application to log the event (because the logger works there). Any ideas?
Thanks,
Mayy
|
|
|
|