' VB6 code ' Primary interface declared as coclass name (without the leading "I"). Dim ws as new SAS.Workspace Dim fref as SAS.Fileref Dim name as string Set fref = ws.FileService.AssignFileref("myfilref", _ "DISK", "c:\myfile.txt", "", name) ' Secondary interface must use COM interface name (requires "I"). ' There is no "SAS.FileInfo" because this is only an interface, ' not an object (coclass). Dim finfo as SAS.IFileInfo ' Call a method on the default interface. debug.print fref.FilerefName ' Obtain a reference to the secondary interface on the object. set finfo = fref ' Make a call using the secondary interface. debug.print finfo.PhysicalName
// C# // Using the "coclass interface" for the workspace and fileref. // The name without the leading "I" came from the COM coclass, // but in .NET it is an interface. SAS.Workspace ws2 = new SAS.Workspace(); // instantiable interface - see below SAS.Fileref fref; String name; fref = ws2.FileService.AssignFileref("myfilref", "DISK", "c:\\myfile.txt", "", out name); // Secondary interface must use COM interface name (requires "I") // There is no "SAS.FileInfo" because this is just an interface, // not an object (coclass). SAS.IFileInfo finfo; // Call a method on the default interface. Trace.Write(fref.FilerefName); // Obtain a reference to the secondary interface on the object. finfo = (SAS.IFileInfo) fref; // Make a call using the secondary interface. Trace.Write(finfo.PhysicalName);
ws
and fref
are the coclass interfaces because
the type library importer created them from the default interface
of the Workspace and Fileref coclasses. finfo
is a .NET interface variable of type IFileinfo—a type that
the type library importer created from the COM IFileInfo interface.
SAS.LanguageService lang = ws.LanguageService; string[] sasPgmLines = { "data _NULL_; ", " infile \'" + filenameBox.Text + "\';", " input;" , " put _infile_;" , "run;" } ; System.Array linesVar = sasPgmLines; // identical to type of ref parm lang.SubmitLines(ref linesVar); bool bMore = true; while (bMore) { System.Array CCs; const int maxLines = 100; System.Array lineTypes; System.Array logLines; lang.FlushLogLines(maxLines, out CCs, out lineTypes, out logLines); for (int i=0; ilogLines.Length; i++) { fileBox.Text += (logLines.GetValue(i) + "\n"); } if (logLines.Length maxLines) bMore = false; }
while
loop might be changed
as follows:
while (bMore) { System.Array CCs; const int maxLines = 100; System.Array lineTypes; System.Array logLinesVar; string []logLines; lang.FlushLogLines(maxLines, out CCs, out lineTypes, out logLinesVar); logLines = (string [])logLinesVar; // explicit conversion for (int i=0; ilogLines.Length; i++) { fileBox.Text += (logLines[i] + "\n"); } if (logLines.Length maxLines) bMore = false; }
while
loop is the ability to
use normal array indexing syntax when accessing the element within
the for
loop. Also, the assignment from logLinesVar
to LogLines required a string[] cast, because the conversion from
the more general System.Array to the specific array type is an explicit
conversion.
for
loops to illustrate array
indexing with each type of array declaration. In practice, simple
loops can be expressed more concisely using the C# FOREACH statement.
Here is an example:
Array optionNames, types, isPortable, isStartupOnly, values, errorIndices, errorCodes, errorMsgs; optionNames=Array.CreateInstance(typeof(string),1); optionNames.SetValue("MLOGIC",0); iOS.GetOptions(ref optionNames, out types, out isPortable, out isStartupOnly, out values, out errorIndices, out errorCodes, out errorMsgs);
while
loop,
the CCs variable is actually an array of enumeration. The type library
importer creates a .NET enumeration type for each COM enumeration
in the type library.
while (bMore) { System.Array CCVar; const int maxLines = 100; System.Array lineTypes; System.Array logLinesVar; string []logLines; SAS.LanguageServiceCarriageControl []CCs; lang.FlushLogLines(maxLines, out CCVar, out lineTypes, out logLinesVar); logLines = (string [])logLinesVar; CCs = (LanguageServiceCarriageControl [])CCVar; for (int i=0; i<logLines.Length; i++) { // Simulate some carriage control with newlines. switch (CCs[i]) { case LanguageServiceCarriageControl. LanguageServiceCarriageControlNewPage: fileBox.Text+="\n\n\n"; break; case LanguageServiceCarriageControl. LanguageServiceCarriageControlSkipTwoLines: fileBox.Text += "\n\n"; break; case LanguageServiceCarriageControl. LanguageServiceCarriageControlSkipLine: fileBox.Text += "\n"; break; case LanguageServiceCarriageControl. LanguageServiceCarriageControlOverPrint: continue; // Don't do overprints. } fileBox.Text += (logLines[i] + '\n'); } if (logLines.Length < maxLines) bMore = false; }
bool bPathError; string styleString = "" + "<xsl:stylesheet xmlns:xsl= " + "\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" + "<xsl:output method=\"text\"/>" + "<xsl:template match=\"SASMessage\">" + "[<xsl:value-of select=\"@severity\"/>] " + "<xsl:value-of select=\".\"/> " + "</xsl:template>" + "</xsl:stylesheet>"; try { ws.DataService.AssignLibref(nameField, engineField, pathField, optionsField); } catch (COMException libnameEx) { switch ((DataServiceERRORS)libnameEx.ErrorCode) { case DataServiceERRORS.DataServiceNoLibrary: bPathError = true; break; } try { // Load the style sheet as an XmlReader. UTF8Encoding utfEnc = new UTF8Encoding(); byte []styleData = utfEnc.GetBytes(styleString); MemoryStream styleStream = new MemoryStream(styleData); XmlReader styleRdr = new XmlTextReader(styleStream); // Load the error message as an XPathDocument. byte []errorData = utfEnc.GetBytes(libnameEx.Message); MemoryStream errorStream = new MemoryStream(errorData); XPathDocument errorDoc = new XPathDocument(errorStream); // Transform to create a message. StringWriter msgStringWriter = new StringWriter(); XslTransform xslt = new XslTransform(); xslt.Load(styleRdr); xslt.Transform(errorDoc,null, msgStringWriter); // Return the resulting error string to the user. errorMsgLabel.Text = msgStringWriter.ToString(); errorMsgLabel.Visible = true; } catch (XmlException) { // Accommodate SAS V8-style error messages with no XML. errorMsgLabel.Text = libnameEx.Message; errorMsgLabel.Visible = true; } }
' This method sends the given data set to the provided workspace, and ' assigns the WebSvc libref to that input data set Private Sub SendData(ByVal obSAS As SAS.Workspace, ByVal inputDS As DataSet) ' Take the provided data set and put it in a fileref in SAS as XML Dim obFileref As SAS.Fileref Dim assignedName As String ' Filename websvc TEMP; obFileref = obSAS.FileService.AssignFileref( "WebSvc", "TEMP", "", "", assignedName) Dim obTextStream As SAS.TextStream obTextStream = obFileref.OpenTextStream( SAS.StreamOpenMode.StreamOpenModeForWriting, 2000) obTextStream.Separator = " " obTextStream.Write("<?xml version=""1.0"" standalone=""yes"" ?>") obTextStream.Write(inputDS.GetXml()) obTextStream.Close() ' An ADO.Net data set is capable of holding multiple tables, schemas, ' and relationships. This sample assumes that the ADO.Net data set ' only contains a single table whose name and columns fit within SAS ' naming rules. This would be an ideal location to use XMLMap to ' transform the schema of the provided data set into something that ' SAS may prefer. ' Here, the default mapping is used. Note that the LIBNAME statement ' uses the fileref of the same name because we did not specify a file. ' Using the IOM method is cleaner than using the Submit because an ' error is returned if there is a problem making the assignment obSAS.DataService.AssignLibref("WebSvc", "XML", "", "") ' obSAS.LanguageService.Submit("libname webSvc XML;") End Sub
' Copy a single SAS data set into a .NET data set Private Function GetData(ByVal obSAS As SAS.Workspace, ByVal sasDataset As String) As DataSet Dim obAdapter As New System.Data.OleDb.OleDbDataAdapter("select * from " & sasDataset, "provider=sas.iomprovider.1; SAS Workspace ID=" & obSAS.UniqueIdentifier) Dim obDS As New DataSet() ' Copy data from the adapter into the data set obAdapter.Fill(obDS, "sasdata") GetData = obDS End Function
private void logDSStart() { progress.Text += "[LanguageService Event] DATASTEP start.\n"; } private void logDSComplete() { progress.Text += "[LanguageService Event] DATASTEP complete.\n"; } private void logProcStart(string procName) { progress.Text += "[LanguageService Event] PROC " + procName + " start.\n"; } private void logProcComplete(string procName) { progress.Text += "[LanguageService Event] PROC " + procName + " complete.\n"; } private void logStepError() { progress.Text += "Step error.\n"; } private void logSubmitComplete(int sasrc) { progress.Text += "[LanguageService Event] Submit complete return code: " + sasrc.ToString() + ".\n"; } // Event listeners use the LanguageService coclass interface. // The Language Service also includes events for the default event interface. SAS.LanguageService lang = ws.LanguageService; lang.DatastepStart += new CILanguageEvents_DatastepStartEventHandler(this.logDSStart); lang.DatastepComplete += new CILanguageEvents_DatastepCompleteEventHandler( this.logDSComplete); lang.ProcStart += new CILanguageEvents_ProcStartEventHandler(this.logProcStart); lang.ProcComplete += new CILanguageEvents_ProcCompleteEventHandler(this.logProcComplete); lang.StepError += new CILanguageEvents_StepErrorEventHandler(this.logStepError); lang.SubmitComplete += new CILanguageEvents_SubmitCompleteEventHandler( this.logSubmitComplete); // Submit source, clear the list and log, etc... // Stop listening. // The "new" operator here is confusing. // Event removal does not really care about the particular // delegate instance. It just looks at the identity of the // listening object and the method being raised. Getting a // new delegate is an easy way to gather that together. SAS.LanguageService lang = ws.LanguageService; lang.DatastepStart -= new CILanguageEvents_DatastepStartEventHandler(this.logDSStart); lang.DatastepComplete -= new CILanguageEvents_DatastepCompleteEventHandler( this.logDSComplete); lang.ProcStart -= new CILanguageEvents_ProcStartEventHandler(this.logProcStart); lang.ProcComplete -= new CILanguageEvents_ProcCompleteEventHandler(this.logProcComplete); lang.StepError -= new CILanguageEvents_StepErrorEventHandler(this.logStepError); lang.SubmitComplete -= new CILanguageEvents_SubmitCompleteEventHandler( this.logSubmitComplete);