Quelltext /~heha/hs/vbs.zip/src/main.cpp

// Von Exe-Programm Excel starten und neue Seite,
// 225 Zellen mit Stringdaten füttern, Zeit messen.

#include "main.h"
#include <ole2.h>
#include <malloc.h>	// _alloca(), erfordert msc.c oder ___chkstk_ms

HINSTANCE ghInstance;
TCHAR MBoxTitle[64];

int vMBox(HWND hParent, UINT uType, const char*msg, va_list va) {
 TCHAR s[125],t[125];
 if (IS_INTRESOURCE(msg)) LoadString(ghInstance,UINT(size_t(msg)),t,elemof(t));
 else
#if UNICODE
	MultiByteToWideChar(CP_ACP,0,msg,-1,t,elemof(t));
#else
	lstrcpyn(t,msg,elemof(t));
#endif
 wvnsprintf(s,elemof(s),t,va);
 return MessageBox(hParent,s,MBoxTitle,uType);
}

int _cdecl MBox(HWND hParent, UINT uType, const char*msg, ...) {
 va_list va;
 va_start(va,msg);
 int ret=vMBox(hParent,uType,msg,va);
 va_end(va);
 return ret;
}

/***************
 * Debug-Hilfe *
 ***************/

static void _cdecl DbgMsg(const char*t,...) {
 va_list va;
 va_start(va,t);
 vMBox(0,MB_OK|MB_ICONEXCLAMATION,t,va);
 va_end(va);
}

#ifdef _DEBUG
# define DbgMsg(x) DbgMsg x
#else
# define DbgMsg(x)
#endif

/*************
 * OLE-Hilfe *
 *************/
HRESULT ghResult;

// VBScript CreateObject() mit Argument in UTF-8
static IDispatch*CreateObject(const char*name) {
 if (!name || !*name) return 0;
 int l=MultiByteToWideChar(CP_UTF8,0,name,-1,0,0);
 WCHAR*pName=(WCHAR*)_alloca(l<<1);
 MultiByteToWideChar(CP_UTF8,0,name,-1,pName,l);
 CLSID clsid;
 if (ghResult=CLSIDFromProgID(pName,&clsid)) {
  DbgMsg(("CLSIDFromProgID(\"%s\") failed with error 0x%08lx",name,ghResult));
  return 0;
 }
 IDispatch*pApp;
 if (ghResult=CoCreateInstance(clsid,0,CLSCTX_LOCAL_SERVER,IID_IDispatch,(void**)&pApp)) {
  DbgMsg(("CoCreateInstance(\"%s\") failed with error 0x%08lx",name,ghResult));
  return 0;
 }
 return pApp;
}

/************************
 * Variant raubkopieren *
 ************************/

static void VariantMove(VARIANT*a,VARIANT*b) {
 if (a==b) return;	// Nichts tun bei gleichen Zeigern (bei __$ReturnUdt-Rückgabe)
 *a=*b;			// memcpy()
 VariantInit(b);	// b.vt=0, sonst nichts
}
static void VariantSwap(VARIANT*a,VARIANT*b) {
 if (a==b) return;	// Nichts tun bei gleichen Zeigern (sollte nie vorkommen)
 VARIANT c=*a;
 *a=*b;
 *b=c;
}

/********************************
 * Automatisch freigebende	*
 * VARIANT-Struktur		*
 ********************************/
struct AutoVariant:public VARIANT{
 AutoVariant() {VariantInit(this);}
 AutoVariant(bool v) {vt=VT_BOOL; boolVal=v?-1:0;}
 AutoVariant(int v) {vt=VT_I4; lVal=v;}			// Zahl-Zuweisung
 AutoVariant(const char*s) {Konstrukt(s,-1);}		// String-Zuweisung: String endet mit NUL
 AutoVariant(const char*s,int l) {Konstrukt(s,l);}	// String-Zuweisung mit Länge = kann NUL enthalten
// Verschiebe-Konstruktor und Verschiebe-Zuweisung steht bei MSVC6 nicht zur Verfügung!
 AutoVariant(VARIANT&o) {VariantMove(this,&o);}
 AutoVariant(AutoVariant&o) {VariantMove(this,&o);}
 ~AutoVariant() {ghResult=VariantClear(this);}
#if __cplusplus >= 201100
 AutoVariant(VARIANT&&o) {VariantMove(this,&o);}	// Raubkopier-Konstruktor
 AutoVariant(AutoVariant&&o) {VariantMove(this,&o);}	// Raubkopier-Konstruktor
 void operator=(const VARIANT&o) = delete;
 void operator=(const AutoVariant&o) = delete;
#endif
private:
 void Konstrukt(const char*s,int l);
};

void AutoVariant::Konstrukt(const char*s,int l) {
 int ul=MultiByteToWideChar(CP_UTF8,0,s,l,0,0);
 if (l<0) --ul;		// ohne Null am Ende
 vt = VT_BSTR;
 bstrVal = SysAllocStringLen(0,ul);
 MultiByteToWideChar(CP_UTF8,0,s,l,bstrVal,ul);
}

AutoVariant vformat(const char*t,va_list va) {
 char s[256];
 int l=wvnsprintfA(s,sizeof s,t,va);
 return AutoVariant(s,l);
}

AutoVariant _cdecl format(const char*t,...) {
 va_list va;
 va_start(va,t);
 return vformat(t,va);
}

/********************************
 * Automatisch freigebendes	*
 * Dispatch-Variant		*
 ********************************/
struct AutoDispatch:public AutoVariant{
// AutoDispatch() {VariantInit(this);}
 inline AutoDispatch(VARIANT&o) {if (o.vt==VT_DISPATCH) VariantMove(this,&o); else VariantInit(this);}
#if __cplusplus >= 201100
 inline AutoDispatch(VARIANT&&o) {if (o.vt==VT_DISPATCH) VariantMove(this,&o); else VariantInit(this);}
#endif 
 inline AutoDispatch(const char*name) {vt=(pdispVal=CreateObject(name))?VT_DISPATCH:0;}
// ~AutoDispatch() {VariantClear() ruft pdispVal->Release();}

// Eigenschafts- und Funktionszugriff.
 inline AutoVariant Get(const char*name) {
  return vWrap(DISPATCH_PROPERTYGET,name,0,0);
 }
 inline AutoVariant Get(const char*name,AutoVariant arg) {
  return vWrap(DISPATCH_PROPERTYGET,name,1,&arg);
 }
 inline void Put(const char*name,AutoVariant arg) {
  vWrap(DISPATCH_PROPERTYPUT,name,1,&arg);
 }
// Für Funktionsaufrufe braucht es ggf. mehr als 0 oder 1 Parameter
 inline AutoVariant operator() (const char*name) {
  return vWrap(DISPATCH_METHOD,name,0,0);
 }
 inline AutoVariant operator() (const char*name,AutoVariant arg) {
  return vWrap(DISPATCH_METHOD,name,1,&arg);
 }
 inline operator bool() {return vt==VT_DISPATCH;}
private:
// vWrap() - Automation helper function
// Can query or set (named) parameters and call named functions
 AutoVariant vWrap(int autoType,const char*name,int argc=0,AutoVariant*argv=0);
};

AutoVariant AutoDispatch::vWrap(int autoType,const char*name,int argc,AutoVariant*argv) {
 AutoVariant UDT(ret);
 VariantInit(&ret);	// Wird vom Aufrufer anscheinend nicht default-konstruiert
 DISPID dispID;

 int l = MultiByteToWideChar(CP_UTF8,0,name,-1,0,0);
 WCHAR*pName = (WCHAR*)_alloca(l<<1);
 MultiByteToWideChar(CP_UTF8,0,name,-1,pName,l);
    // Get DISPID for name passed...
 ghResult = pdispVal->GetIDsOfNames(IID_NULL,&pName,1,LOCALE_USER_DEFAULT,&dispID);
 if (FAILED(ghResult)) {
  DbgMsg(("IDispatch::GetIDsOfNames(\"%s\") failed with error 0x%08lX",name,ghResult));
 }else{
  DISPID dispidNamed = DISPID_PROPERTYPUT;
    // Variables used...
  DISPPARAMS dp = {
	argv,
	&dispidNamed,
	(UINT)argc,
	autoType&DISPATCH_PROPERTYPUT ? 1U : 0
  };
    // Make the call!
  ghResult = pdispVal->Invoke(dispID,IID_NULL,LOCALE_SYSTEM_DEFAULT,autoType,&dp,&ret,0,0);
  if (FAILED(ghResult)) {
   DbgMsg(("IDispatch::Invoke(\"%s\"=%08lx) failed with error 0x%08lx",name,dispID,ghResult));
  }
 }
 return ret;
}


/*****************
 * Hauptprogramm *
 *****************/
// Es zeigt wie lahm Excel startet
// aber auch wie schnell große Datenmengen
// in Excel-Tabellen eingesetzt werden können!
// Letzteres ist in VBA und VBScript kaum so schnell.

static int mymain() {
 if (!CoInitialize(0)) {
  DWORD t0=GetTickCount(),t1,t2;
// Keine Zeiger, nur Autopointer!
// Mit den Autopointern sieht dieses Programm schon skript-ähnlich aus.
  AutoDispatch XlApp("Excel.Application");
  if (XlApp) {
// Der <true>-Parameter ruft den AutoVariant-Konstruktor auf.
   XlApp.Put("Visible",true);
// Und das Semikolon ruft den AutoVariant-Destruktor!
// Denn damit endet der Gültigkeitbereich des anonymen AutoVariant.
   AutoDispatch(XlApp.Get("ErrorCheckingOptions")).Put("BackgroundChecking",false);
  // Get Workbooks collection
// Da AutoDispatch von AutoVariant erbt, braucht es hier keinen Typecast.
// Eine Zuweisung ruft hier den Raubkopier-Konstruktor auf
   AutoDispatch XlBooks(XlApp.Get("Workbooks"));
   // Call Workbooks.Add() to get a new workbook...
   AutoDispatch XlBook(XlBooks.Get("Add"));
   // Get ActiveSheet object
   {AutoDispatch XlSheet(XlApp.Get("ActiveSheet"));
    t1=GetTickCount();
   // Create a 15x15 safearray of variants...
    {AutoVariant arr;
     arr.vt = VT_ARRAY | VT_VARIANT;
     SAFEARRAYBOUND sab[2];
     sab[0].lLbound = 1; sab[0].cElements = 15;
     sab[1].lLbound = 1; sab[1].cElements = 15;
     arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);

   // Fill safearray with values...
     for(int i=1; i<=15; i++)
     for(int j=1; j<=15; j++) {
         // Create entry value for (i,j)
// Die printf-ähnliche Funktion generiert sogleich eine BSTR-Variante.
         // Add to safearray...
      long indices[] = {i,j};
// Anonyme Variante mit Konstruktor in format() ... Zeigerreferenz eines temporären Objekts verboten in C++11
      AutoVariant t = format("'%u",i*j);
      SafeArrayPutElement(arr.parray,indices,&t);
     }	// Diese Klammer ruft den Destruktor von t und arr
   // Get Range object for the Range A1:O15...
     AutoDispatch XlRange(XlSheet.Get("Range","A1:O15"));
   // Set range with our safearray...
     XlRange.Put("Value",arr);
    }	// Diese Klammer ruft den Destruktor von <arr> und <XlRange>
    t2=GetTickCount();
    AutoDispatch(XlSheet.Get("Columns","A:O"))("AutoFit");
   }
   // Set .Saved property of workbook to TRUE so we aren't prompted
   // to save when we tell Excel to quit...
   if (false) XlBook.Put("Saved",true);
   else XlApp.Put("DisplayAlerts",false);

   // Inform and wait for user...
   MBox(0,MB_OK|MB_ICONINFORMATION,(const char*)2,DWORD(t1-t0),DWORD(t2-t1));	// "Startup time, fill time"
   // Die Startleiste stellt währenddessen ohne Zutun das App-Icon dar

   // Tell Excel to quit (i.e. App.Quit)
   XlApp("Quit");
  }else{
   MBox(0,MB_OK|MB_ICONEXCLAMATION,(const char*)3);	// "No excel automation server found"
  }
   // Uninitialize COM for this thread...
  CoUninitialize();
 }else DbgMsg(("CoInitialize failed with error %d",GetLastError()));
 return 0;
}

#ifdef _MSC_VER
void CALLBACK
#else //mingw
extern "C" void ___chkstk_ms() {}
// Genauso wie bei MSVC wird _alloca() mit einer Hilfsfunktion compiliert.
// ___chkstk_ms bekommt in rax die benötigte Stack-Größe
// bereits auf volle 16 Byte aufgerundet.
// Müsste den Stack in 4-KByte-Stückelung touchen.
// Liefert rax unverändert zurück.
// Da die Allokationsgrößen bei _alloca() in diesem Programm mickrig sind,
// tut diese Funktion hier einfach nichts.
extern "C" void
#endif
	WinMainCRTStartup() {
 ghInstance = GetModuleHandle(0);
 LoadString(ghInstance,1,MBoxTitle,elemof(MBoxTitle));
 ExitProcess(mymain());
}
Vorgefundene Kodierung: ANSI (CP1252)4
Umlaute falsch? - Datei sei ANSI-kodiert (CP1252)