
Tengo la necesidad de encapsular un componente de terceros (TComPort) dentro de una DLL para que pueda ser usado desde otra aplicacion (VB.net), NO es solo el componente serial lo que me interesa pues en C# y VB.net existe una libreria (¡al fin lo dije sin esperar un regaño!) para tal fin, son las funciones añadidas las que realmente daran valor a la dll. Por el momento me he centrado en la funcion del puerto de comunicaciones y no he podido pasar de ahi. Con el codigo que actualmente tengo abro, cierro, cambio ajustes del puerto serie, mi problema radica en que los procedimientos de Salvar y guardar los cambios a la configuracion no me funcionan, me genera un error. Dichos datos de configuracion se guardan a discrecion en un archivo INI o en el registro, yo he seleccionado INI por la facilidad de hacer cambios sin necesidad de ser administrador. Pues bien, el archivo INI SI se crea pero el error que me genera es que no ha podido escribir la aplicacion nada en el.
Esta es mi DLL:
delphi
library comScale; { Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select Project-View Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the BORLNDMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using BORLNDMM.DLL, pass string information using PChar or ShortString parameters. } uses SysUtils, Classes, Forms, Dialogs, CPort; {$R *.res} var PuertoS: TComPort; num: integer; function CrearPuerto: boolean; stdCall; begin Result := True; try PuertoS := TComPort.Create(Application); PuertoS.TriggersOnRxChar := True; PuertoS.EventThreadPriority := tpNormal; PuertoS.Port := 'Com1'; PuertoS.BaudRate := br9600; PuertoS.Parity.Bits := prNone; PuertoS.StopBits := sbOneStopBit; PuertoS.DataBits := dbEight; PuertoS.Events := [evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR, evError, evRLSD, evRx80Full]; PuertoS.StoredProps := [spBasic]; PuertoS.FlowControl.OutCTSFlow := False; PuertoS.FlowControl.OutDSRFlow := False; PuertoS.FlowControl.ControlDTR := dtrDisable; PuertoS.FlowControl.ControlRTS := rtsDisable; PuertoS.FlowControl.XonXoffOut := False; PuertoS.FlowControl.XonXoffIn := False; except Result := false; Showmessage('Imposible crear el puerto de comunicaciones'); end; end; procedure DestruirPuerto; stdCall; begin PuertoS.Free ; end; function AbrirPuerto : boolean; stdCall; begin Result := True; try PuertoS.Open ; except Result := false; ShowMessage('Imposible abrir el puerto de comunicaciones'); end; end; function CerrarPuerto : boolean; stdCall; begin result := true; try If PuertoS.Connected then PuertoS.Close ; except result := false; end; end; procedure GuardarCFG(archivo: PChar); stdCall; begin PuertoS.StoreSettings(stIniFile, strPas(Archivo)); end; procedure CargarCFG(archivo: PChar); stdCall; begin PuertoS.LoadSettings(stIniFile, strPas(Archivo)); end; procedure MuestraSetup; stdCall; begin PuertoS.ShowSetupDialog ; end; function AjustesActuales : PChar; stdCall; begin Result := PChar(PuertoS.Port + ',' + BaudRatetoStr(PuertoS.BaudRate) + ',' + DataBitsToStr(PuertoS.DataBits) + ',' + ParityToStr(PuertoS.Parity.Bits) + ',' + StopBitstoStr(PuertoS.StopBits)); end; exports CrearPuerto, AbrirPuerto, CerrarPuerto, GuardarCFG, CargarCFG, MuestraSetup, AjustesActuales; begin end.
Este es el ejemplo de uso (1 formulario con un statusbar y un panel que contiene 7 botones ):
delphi
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, IniFiles; type TForm1 = class(TForm) Panel1: TPanel; btnCrear: TButton; btnAbrir: TButton; btnCerrar: TButton; btnCfg: TButton; btnStoreCFG: TButton; btnLoadCFG: TButton; StatusBar1: TStatusBar; btnMuestra: TButton; procedure btnCrearClick(Sender: TObject); procedure btnAbrirClick(Sender: TObject); procedure btnCerrarClick(Sender: TObject); procedure btnCfgClick(Sender: TObject); procedure btnMuestraClick(Sender: TObject); procedure btnStoreCFGClick(Sender: TObject); procedure btnLoadCFGClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; function CrearPuerto: boolean; stdcall; external 'ComScale.dll'; procedure DestruyePuerto; stdcall; external 'ComScale.dll'; function AbrirPuerto: boolean; stdcall; external 'ComScale.dll'; function CerrarPuerto: boolean; stdcall; external 'ComScale.dll'; procedure MuestraSetup; stdcall; external 'ComScale.dll'; procedure CargarCFG(archivo: PChar); stdcall; external 'ComScale.dll'; procedure GuardarCFG(archivo: PChar); stdcall; external 'ComScale.dll'; function AjustesActuales: PChar; stdcall; external 'ComScale.dll'; implementation {$R *.dfm} procedure TForm1.btnCrearClick(Sender: TObject); begin if CrearPuerto then StatusBar1.Panels[0].Text := 'Puerto Creado'; end; procedure TForm1.btnAbrirClick(Sender: TObject); begin if AbrirPuerto then StatusBar1.Panels[1].Text := 'Conectado'; end; procedure TForm1.btnCerrarClick(Sender: TObject); begin if CerrarPuerto then StatusBar1.Panels[1].Text := 'Desconectado'; end; procedure TForm1.btnCfgClick(Sender: TObject); begin MuestraSetup; end; procedure TForm1.btnStoreCFGClick(Sender: TObject); var Archivo: string; begin Archivo := ExtractFilePath(ParamStr(0)) + 'CommCfg.ini'; GuardarCFG(pchar(Archivo)); end; procedure TForm1.btnLoadCFGClick(Sender: TObject); var Archivo: string; begin Archivo := ExtractFilePath(ParamStr(0)) + 'CommCfg.ini'; CargarCFG(pchar(Archivo)); end; procedure TForm1.btnMuestraClick(Sender: TObject); begin StatusBar1.Panels[2].Text := AjustesActuales; end; end.
Todos los procedimientos me funcionan salvo los de guardar (btnStoreCFGClick) y Cargar (btnLoadCFGClick); aqui debo puntualizar que el de guardar es el unico que he usado pues es el que crea el archivo INI el de cargar no lo he usado pues al no existir el ini no hace nada.
Este es el procedimiento del ComPort para guardar en un INI:
delphi
procedure TCustomComPort.StoreIniFile(IniFile: TIniFile); begin if spBasic in FStoredProps then begin IniFile.WriteString(Name, 'Port', Port); IniFile.WriteString(Name, 'BaudRate', BaudRateToStr(BaudRate)); if BaudRate = brCustom then IniFile.WriteInteger(Name, 'CustomBaudRate', CustomBaudRate); IniFile.WriteString(Name, 'StopBits', StopBitsToStr(StopBits)); IniFile.WriteString(Name, 'DataBits', DataBitsToStr(DataBits)); IniFile.WriteString(Name, 'Parity', ParityToStr(Parity.Bits)); IniFile.WriteString(Name, 'FlowControl', FlowControlToStr(FlowControl.FlowControl)); end; if spOthers in FStoredProps then begin IniFile.WriteString(Name, 'EventChar', CharToStr(EventChar)); IniFile.WriteString(Name, 'DiscardNull', BoolToStr(DiscardNull)); end; if spParity in FStoredProps then begin IniFile.WriteString(Name, 'Parity.Check', BoolToStr(Parity.Check)); IniFile.WriteString(Name, 'Parity.Replace', BoolToStr(Parity.Replace)); IniFile.WriteString(Name, 'Parity.ReplaceChar', CharToStr(Parity.ReplaceChar)); end; if spBuffer in FStoredProps then begin IniFile.WriteInteger(Name, 'Buffer.OutputSize', Buffer.OutputSize); IniFile.WriteInteger(Name, 'Buffer.InputSize', Buffer.InputSize); end; if spTimeouts in FStoredProps then begin IniFile.WriteInteger(Name, 'Timeouts.ReadInterval', Timeouts.ReadInterval); IniFile.WriteInteger(Name, 'Timeouts.ReadTotalConstant', Timeouts.ReadTotalConstant); IniFile.WriteInteger(Name, 'Timeouts.ReadTotalMultiplier', Timeouts.ReadTotalMultiplier); IniFile.WriteInteger(Name, 'Timeouts.WriteTotalConstant', Timeouts.WriteTotalConstant); IniFile.WriteInteger(Name, 'Timeouts.WriteTotalMultiplier', Timeouts.WriteTotalMultiplier); end; if spFlowControl in FStoredProps then begin IniFile.WriteString(Name, 'FlowControl.ControlRTS', RTSToStr(FlowControl.ControlRTS)); IniFile.WriteString(Name, 'FlowControl.ControlDTR', DTRToStr(FlowControl.ControlDTR)); IniFile.WriteString(Name, 'FlowControl.DSRSensitivity', BoolToStr(FlowControl.DSRSensitivity)); IniFile.WriteString(Name, 'FlowControl.OutCTSFlow', BoolToStr(FlowControl.OutCTSFlow)); IniFile.WriteString(Name, 'FlowControl.OutDSRFlow', BoolToStr(FlowControl.OutDSRFlow)); IniFile.WriteString(Name, 'FlowControl.TxContinueOnXoff', BoolToStr(FlowControl.TxContinueOnXoff)); IniFile.WriteString(Name, 'FlowControl.XonXoffIn', BoolToStr(FlowControl.XonXoffIn)); IniFile.WriteString(Name, 'FlowControl.XonXoffOut', BoolToStr(FlowControl.XonXoffOut)); IniFile.WriteString(Name, 'FlowControl.XoffChar', CharToStr(FlowControl.XoffChar)); IniFile.WriteString(Name, 'FlowControl.XonChar', CharToStr(FlowControl.XonChar)); end; end;
Razonando un poco me pregunto si el problema no estara en los IniFile.WriteString que debieran ser convertidos a PChar, pero ahi entonces ¿Como se hace eso?
Se que para muchos al no tener en su PC un puerto serie pues esto les generaria un error pero si pueden cuando menos echarle un ojo...
¡¡Ilustres maestros os imploro ayuda!! ¡¡Dejen un rato de adorar a Baco y regresen al oraculo de Delphos!!