C++ Optimization breaking OLE Automation program (non-MFC)

0

I'm writing a program to parse a Word Document and export data out to an Excel Workbook using OLE Automation (the non-MFC way I guess). Works fine in Debug, not so in Release (specifically if optimization is enabled). The error is that the IDispatch::Invoke call failed, specifically:

0x80020004 DISP_E_PARAMNOTFOUND Parameter not found

I checked StackOverflow for some suggestions and the main one seems to be uninitialized variables. That might be what's going on, but I still don't understand this specific case. I've narrowed it down to a single function in my program Automation::Dispatch::Invoke which is responsible for finally calling IDispatch::Invoke. The arguments being passed into Automation::Dispatch::Invoke are correct so the problem is somewhere in its code.

Looking at the base code (from MSDN) that I adapted this from, I was able to get it working and narrow down the exact problem line. Below shows code that does not work, but the comments indicate the line that I moved to get it working (look for the 2 lines with a <--- Problem line comment). In Debug mode, the location of this line does not matter and it works in either spot.


My question is what does this fix, and why is it an issue to start with? Thank you and let me know if I can make the question more clear.


HRESULT Automation::Dispatch::Invoke(int cmd, std::string name, std::vector<VARIANT> values)
{
  USES_CONVERSION;
  HRESULT result;

  /* Get DISPID for name passed */
  DISPID dispID;
  LPOLESTR nameOle=A2OLE(name.c_str());
  result=pObjectInt->GetIDsOfNames(IID_NULL, &nameOle, 1, LOCALE_USER_DEFAULT, &dispID);
  if (FAILED(result)) {
    return result;
  }
  /* Reverse elements in values vector so they are invoked in the correct order */
  std::reverse(values.begin(), values.end());

  /* Allocate memory for object values */
  VARIANT *pValues=new VARIANT[values.size() + 1];
  for (unsigned int i=0; i < values.size(); ++i) {
    pValues[i]=values[i];
  }
  /* Build DISPPARAMS */
  DISPPARAMS dispParams= {NULL, NULL, 0, 0};
  /* DISPID dispidNamed=DISPID_PROPERTYPUT;   <--- PROBLEM LINE moved here makes it work */
  dispParams.cArgs=values.size();
  dispParams.rgvarg=pValues;

  /* Handle special-case for property-puts */
  if (cmd==DISPATCH_PROPERTYPUT) {
    DISPID dispidNamed=DISPID_PROPERTYPUT;   /* <--- PROBLEM LINE here */
    dispParams.cNamedArgs=1;
    dispParams.rgdispidNamedArgs=&dispidNamed;
  }
  /* Make the call */
  if (cmd==DISPATCH_METHOD || cmd==DISPATCH_PROPERTYPUT) {
    result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, NULL, NULL, NULL);
  }
  else {
    VariantInit(&objectData);
    result=pObjectInt->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, cmd, &dispParams, &objectData, NULL, NULL);
  }
  delete[] pValues;
  return result;
}

c++
optimization
visual-studio-2013
ole
office-automation
asked on Stack Overflow Jun 2, 2015 by donkrx

1 Answer

1

In this code:

if (cmd==DISPATCH_PROPERTYPUT) {
    DISPID dispidNamed=DISPID_PROPERTYPUT;   /* <--- PROBLEM LINE here */
    dispParams.cNamedArgs=1;
    dispParams.rgdispidNamedArgs=&dispidNamed;
}

dispidNamed is a local variable to the code block it is in (i.e. the area delimited by { }).

After the } is reached it ceases to exist. Then rgdispidNamedArgs is a dangling pointer because it no longer points to a variable that exists.

You got unlucky in Debug mode that it didn't trigger an error sooner.

answered on Stack Overflow Jun 2, 2015 by M.M

User contributions licensed under CC BY-SA 3.0